﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using Model;

// NOTE: Update methods write to client | Refresh methods read from client or reclculate

public partial class MainForm : Form
{
    // TODO Search in hidden Simplified29 text and show result in Original
    // TODO Make 37-key Keybpard like Standard Edition

    // TextBox has no Ctrl+A by default, so add it
    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (ModifierKeys == Keys.Control)
        {
            if (e.KeyCode == Keys.A)
            {
                if (sender is TextBoxBase)
                {
                    (sender as TextBoxBase).SelectAll();
                }
            }
        }
        else
        {
            if (e.KeyCode == Keys.Tab)
            {
                e.Handled = true;
            }
        }
    }
    private void FixMicrosoft(object sender, KeyPressEventArgs e)
    {
        // stop annoying beep due to parent not having an AcceptButton
        if ((e.KeyChar == (char)Keys.Enter) || (e.KeyChar == (char)Keys.Escape))
        {
            e.Handled = true;
        }
        // enable Ctrl+A to SelectAll
        if ((ModifierKeys == Keys.Control) && (e.KeyChar == (char)1))
        {
            TextBoxBase control = (sender as TextBoxBase);
            if (control != null)
            {
                control.SelectAll();
                e.Handled = true;
            }
        }
    }

    private const int DEFAULT_WINDOW_WIDTH = 840;
    private const int DEFAULT_WINDOW_HEIGHT = 627;
    private const int DEFAULT_TRANSLATION_BOX_TOP = 379;
    private const float DEFAULT_FONT_SIZE = 14.0F;
    private const float DEFAULT_TEXT_ZOOM_FACTOR = 1.0F;
    private const bool DEFAULT_ACTIVE_WORDS = true;
    private const int DEFAULT_AUDIO_VOLUME = 1000;
    private const float DEFAULT_SILENCE_BETWEEN_VERSES = 0.0F; // in multiples of verses
    private const string CAPTION_SEPARATOR = " ► ";
    private const float DEFAULT_DPI_X = 96.0F; // 100% = 96.0F,   125% = 120.0F,   150% = 144.0F
    //private const float DEFAULT_DPI_Y = 96.0F;
    private float m_dpi_x = DEFAULT_DPI_X;
    //private float m_dpi_y = DEFAULT_DPI_Y;

    private Font m_font = null;
    private float m_font_size = DEFAULT_FONT_SIZE;
    private void SetFontSize(float size)
    {
        if (m_font == null)
        {
            m_font = FontBuilder.Build("ActiveQuran.Fonts.me_quran.ttf", size);
            //m_font = FontBuilder.Build(ActiveQuran.Fonts.uthmani.otf", size * 2);
            //m_font = FontBuilder.Build(ActiveQuran.Fonts.akshar.ttf", size);
        }
        else
        {
            m_font = new Font("me_quran.ttf", size);
            //m_font = new Font("uthmani.otf", size * 2);
            //m_font = new Font("akshar.ttf", size);
        }
        MainTextBox.Font = m_font;
        MainTextBox.Refresh();
    }

    private int m_translation_box_top = DEFAULT_TRANSLATION_BOX_TOP;

    private string m_ini_filename = "";

    private Client m_client = null;
    private string m_current_text = "";

    public MainForm()
    {
        try
        {
            this.Cursor = Cursors.WaitCursor;

            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);

            using (Graphics graphics = this.CreateGraphics())
            {
                m_dpi_x = graphics.DpiX;
                //m_dpi_y = graphics.DpiY;
                if (m_dpi_x != DEFAULT_DPI_X)
                {
                    if (m_dpi_x == 120.0F)
                    {
                        // adjust GUI to fit into 125%
                        MainSplitContainer.Height = (int)(MainSplitContainer.Height / (m_dpi_x / DEFAULT_DPI_X)) + 96;
                        //MainSplitContainer.Width = (int)(MainSplitContainer.Width / (m_dpi_x / DEFAULT_DPI_X)) - 46;
                        MainSplitContainer.SplitterDistance = 215;
                    }
                }
            }

            m_ini_filename = AppDomain.CurrentDomain.FriendlyName.Replace(".exe", ".ini");

            this.MainTextBox.HideSelection = false; // this won't shift the text to the left
            //this.MainTextBox.HideSelection = true; // this WILL shift the text to the left
            this.MainTextBox.MouseWheel += new MouseEventHandler(MainTextBox_MouseWheel);
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void MainForm_Load(object sender, EventArgs e)
    {
        bool splash_screen_done = false;
        try
        {
            SplashForm splash_form = new SplashForm();
            ThreadPool.QueueUserWorkItem(delegate
            {
                using (splash_form)
                {
                    splash_form.Show();
                    while (!splash_screen_done)
                    {
                        Application.DoEvents();
                    }
                    splash_form.Close();
                }
            }, null);

            try
            {
                VersionLabel.Text = "v" + Application.ProductVersion.Substring(0, 5);
                splash_form.Version += " - " + VersionLabel.Text;

                InitializeControls();
                splash_form.Information = "Initializing server ...";
                splash_form.Progress = 20;
                Thread.Sleep(100);

                m_client = new Client();
                if (m_client != null)
                {
                    splash_form.Information = "Building translations ...";
                    PopulateTranslatorsCheckedListBox();
                    PopulateTranslatorComboBox();
                    splash_form.Progress = 40;
                    Thread.Sleep(100);

                    splash_form.Information = "Building recitations ...";
                    PopulateRecitationsCheckedListBox();
                    PopulateRecitationsComboBox();
                    splash_form.Progress = 80;
                    Thread.Sleep(100);

                    // must be done before LoadApplicationSettings
                    splash_form.Information = "Loading bookmarks ...";
                    m_client.LoadBookmarks();
                    UpdateBookmarkHistoryButtons();
                    splash_form.Progress = 85;
                    Thread.Sleep(100);

                    splash_form.Information = "Loading application settings ...";
                    LoadApplicationSettings();
                    splash_form.Progress = 95;
                    Thread.Sleep(100);

                    splash_form.Information = "Loading user history ...";
                    m_client.LoadHistoryItems();
                    UpdateBrowseHistoryButtons();
                    splash_form.Progress = 100;
                    Thread.Sleep(100);
                }

                DisplaySelection(false);

                splash_form.Information = "Starting ...";
                Thread.Sleep(200);

                // prepare before Shown
                this.ClientSplitContainer.SplitterDistance = m_translation_box_top;
                MainTextBox_ToggleWordWrap(); // add/remove Verse.EndMark, wrap/unwrap and redisplay

                this.Activate(); // bring to foreground
            }
            finally
            {
                splash_screen_done = true;
                Thread.Sleep(100);  // prevent race-condition to allow splashform.Close()
            }
        }
        catch (Exception ex)
        {
            while (ex != null)
            {
                MessageBox.Show(ex.Message, Application.ProductName);
                ex = ex.InnerException;
            }
        }
    }
    private void MainForm_Shown(object sender, EventArgs e)
    {
        try
        {
            MainTextBox.AlignToStart();

            if (RecitationsComboBox.SelectedItem != null)
            {
                RecitationGroupBox.Text = RecitationsComboBox.SelectedItem.ToString() + "                         ";
            }

            this.ActiveControl = MainTextBox;
        }
        catch (Exception ex)
        {
            while (ex != null)
            {
                //Console.WriteLine(ex.Message);
                MessageBox.Show(ex.Message, Application.ProductName);
                ex = ex.InnerException;
            }
        }
    }
    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            e.Handled = false;
        }
        if (e.KeyCode == Keys.Space)
        {
            if ((MainTextBox.Focused) && (!MainTextBox.ReadOnly)) return;
            if (ChapterComboBox.Focused) return;
            if (BookmarkTextBox.Focused) return;
            if ((m_mp3player.Playing) || (m_mp3player.Paused))
            {
                PlayerPlayLabel_Click(null, null);
                // TODO stop annoying beep of Space key for pause/resume
                // FixMicrosoft didn't word work !!!
            }
        }
        else if (e.KeyCode == Keys.Escape)
        {
            HandleEscapeKeyPress(sender, null);
        }
        else if (e.Control && (e.KeyCode == Keys.Down))
        {
        }
        else if (e.Control && (e.KeyCode == Keys.Up))
        {
        }
        else
        {
            // do nothing
        }

        if (!e.Alt && !e.Control && !e.Shift)
        {
            if ((e.KeyCode == Keys.Back) || (e.KeyCode == Keys.BrowserBack))
            {
                if ((sender == MainTextBox) && (MainTextBox.ReadOnly))
                {
                    BrowseHistoryBackwardButton_Click(null, null);
                }
            }
            else if ((e.KeyCode == Keys.BrowserForward))
            {
                if ((sender == MainTextBox) && (MainTextBox.ReadOnly))
                {
                    BrowseHistoryForwardButton_Click(null, null);
                }
            }
            else if (e.KeyCode == Keys.F1)
            {
            }
            else if (e.KeyCode == Keys.F2)
            {
                NextBookmarkButton_Click(null, null);
            }
            else if (e.KeyCode == Keys.F3)
            {
                if (m_found_verses_displayed)
                {
                    FindNextMatch();
                }
            }
            else if (e.KeyCode == Keys.F4)
            {
            }
            else if (e.KeyCode == Keys.F5)
            {
                if (MainTextBox.Focused)
                {
                    DoFindExactMatch(MainTextBox);
                }
            }
            else if (e.KeyCode == Keys.F6)
            {
                if (MainTextBox.Focused)
                {
                    DoFindSimilarWords(MainTextBox);
                }
            }
            else if (e.KeyCode == Keys.F7)
            {
                if (MainTextBox.Focused)
                {
                    DoFindRelatedWords(MainTextBox);
                }
            }
            else if (e.KeyCode == Keys.F8)
            {
            }
            else if (e.KeyCode == Keys.F9)
            {
            }
            else if (e.KeyCode == Keys.F10)
            {
                DoGotoVerse();
            }
            else if (e.KeyCode == Keys.F11)
            {
                MainTextBox_ToggleWordWrap(); // add/remove Verse.EndMark, wrap/unwrap and redisplay
            }
            else if (e.KeyCode == Keys.F12)
            {
                if (this.WindowState != FormWindowState.Maximized)
                {
                    this.WindowState = FormWindowState.Maximized;
                    this.FormBorderStyle = FormBorderStyle.None;
                }
                else
                {
                    this.WindowState = FormWindowState.Normal;
                    this.FormBorderStyle = FormBorderStyle.Sizable;
                }
            }
            else
            {
                // ignore key
            }
        }
        else if (!e.Alt && !e.Control && e.Shift)
        {
            if ((e.KeyCode == Keys.Back) || (e.KeyCode == Keys.BrowserBack))
            {
                if (MainTextBox.ReadOnly)
                {
                    if ((sender == MainTextBox) && (MainTextBox.ReadOnly))
                    {
                        BrowseHistoryForwardButton_Click(null, null);
                    }
                }
            }
            else if ((e.KeyCode == Keys.BrowserForward))
            {
                if ((sender == MainTextBox) && (MainTextBox.ReadOnly))
                {
                    BrowseHistoryBackwardButton_Click(null, null);
                }
            }
            else if (e.KeyCode == Keys.F1)
            {
            }
            else if (e.KeyCode == Keys.F2)
            {
                PreviousBookmarkButton_Click(null, null);
            }
            else if (e.KeyCode == Keys.F3)
            {
                if (m_found_verses_displayed)
                {
                    FindPreviousMatch();
                }
            }
            else if (e.KeyCode == Keys.F4)
            {
            }
            else if (e.KeyCode == Keys.F5)
            {
            }
            else if (e.KeyCode == Keys.F6)
            {
            }
            else if (e.KeyCode == Keys.F7)
            {
            }
            else if (e.KeyCode == Keys.F8)
            {
            }
            else if (e.KeyCode == Keys.F9)
            {
            }
            else if (e.KeyCode == Keys.F10)
            {
            }
            else if (e.KeyCode == Keys.F11)
            {
            }
            else if (e.KeyCode == Keys.F12)
            {
            }
            else
            {
                // ignore key
            }
        }
        else
        {
            // ignore key
        }
    }
    private void MainForm_Resize(object sender, EventArgs e)
    {
        if (MainTextBox.SelectionStart == 0)
        {
            // move cursor to top and lose any selection
            MainTextBox.AlignToLineStart();
        }
    }
    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        //// prevent user from closing from the X close button
        //if (e.CloseReason == CloseReason.UserClosing)
        //{
        //    e.Cancel = true;
        //    this.Visible = false;
        //}
    }
    private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
    {
        CloseApplication();
    }
    private void CloseApplication()
    {
        if (m_client != null)
        {
            try
            {
                // save current note (if any)
                BookmarkTextBox_Leave(null, null);

                // save bookmarks of all texts of current client
                m_client.SaveBookmarks();

                // save user history
                m_client.SaveHistoryItems();

                // save application options
                SaveApplicationOptions();
            }
            catch
            {
                // silence IO error in case running from read-only media (CD/DVD)
            }
        }
    }
    private void HandleEscapeKeyPress(object sender, KeyEventArgs e)
    {
        // back line indexes
        int backup_current_line_index = m_current_line_index;
        int backup_found_verses_current_line_index = m_found_verses_current_line_index;

        if (sender == BookmarkTextBox)
        {
            BookmarkTextBox.Text = "";
            BookmarkTextBox_Leave(null, null);
        }
        else
        {
            if (m_found_verses_displayed)
            {
                DisplaySelection(false);
            }
            else
            {
                if (m_client != null)
                {
                    if (m_client.HistoryItems != null)
                    {
                        if (m_client.HistoryItems.Count > 0)
                        {
                            DisplayBrowseHistoryItem(m_client.CurrentHistoryItem as FindHistoryItem);
                        }
                    }
                }
            }
        }

        // restore line indexes
        m_current_line_index = backup_current_line_index;
        m_found_verses_current_line_index = backup_found_verses_current_line_index;

        int line_index = -1;
        if (m_found_verses_displayed)
        {
            line_index = m_found_verses_current_line_index;
        }
        else
        {
            line_index = m_current_line_index;
        }
        GotoLine(line_index);
    }
    private void UpdateVersesToCurrentTextMode(ref List<Verse> verses)
    {
        List<Verse> temp = new List<Verse>();
        foreach (Verse verse in verses)
        {
            temp.Add(m_client.Book.Verses[verse.Number - 1]);
        }
        verses = temp;
    }
    private void LoadApplicationSettings()
    {
        try
        {
            PopulateChapterComboBox();
            PopulateChaptersListBox();
            PopulateRecitationsComboBox();
            PopulateTranslatorComboBox();

            LoadApplicationOptions();

            DisplaySelection(false);

            PlayerVolumeTrackBar.Value = m_audio_volume / (1000 / PlayerVolumeTrackBar.Maximum);
            PlayerSilenceTrackBar.Value = (int)(m_silence_between_verses * (PlayerSilenceTrackBar.Maximum / 2));
        }
        catch (Exception ex)
        {
            while (ex != null)
            {
                //Console.WriteLine(ex.Message);
                MessageBox.Show(ex.Message, Application.ProductName);
                ex = ex.InnerException;
            }
        }
    }
    private void LoadApplicationOptions()
    {
        if (File.Exists(m_ini_filename))
        {
            try
            {
                if (m_client != null)
                {
                    // Selection.Scope and Selection.Indexes are immutable/readonly so create a new Selection to replace m_client.Selection 
                    SelectionScope selection_scope = SelectionScope.Book;
                    List<int> selection_indexes = new List<int>();

                    using (StreamReader reader = File.OpenText(m_ini_filename))
                    {
                        while (!reader.EndOfStream)
                        {
                            string line = reader.ReadLine();
                            string[] parts = line.Split('=');
                            if (parts.Length == 2)
                            {
                                switch (parts[0])
                                {
                                    // [Window]
                                    case "Top":
                                        {
                                            try
                                            {
                                                this.Top = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                this.Top = 100;
                                            }
                                        }
                                        break;
                                    case "Left":
                                        {
                                            try
                                            {
                                                this.Left = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                this.Left = 100;
                                            }
                                        }
                                        break;
                                    case "Width":
                                        {
                                            try
                                            {
                                                this.Width = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                this.Width = DEFAULT_WINDOW_WIDTH;
                                            }
                                        }
                                        break;
                                    case "Height":
                                        {
                                            try
                                            {
                                                this.Height = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                this.Height = DEFAULT_WINDOW_HEIGHT;
                                            }
                                        }
                                        break;
                                    case "TranslationBoxTop":
                                        {
                                            try
                                            {
                                                m_translation_box_top = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                m_translation_box_top = DEFAULT_TRANSLATION_BOX_TOP;
                                            }
                                        }
                                        break;
                                    // [Text]
                                    case "WordWrap":
                                        {
                                            try
                                            {
                                                MainTextBox.WordWrap = !bool.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                MainTextBox.WordWrap = false;
                                            }
                                        }
                                        break;
                                    case "SelectionScope":
                                        {
                                            try
                                            {
                                                selection_scope = (SelectionScope)Enum.Parse(typeof(SelectionScope), parts[1].Trim());
                                            }
                                            catch
                                            {
                                                selection_scope = SelectionScope.Chapter;
                                            }
                                        }
                                        break;
                                    case "SelectionIndexes":
                                        {
                                            try
                                            {
                                                string part = parts[1].Trim();
                                                string[] sub_parts = part.Split('+');
                                                selection_indexes.Clear();
                                                for (int i = 0; i < sub_parts.Length; i++)
                                                {
                                                    try
                                                    {
                                                        int index = int.Parse(sub_parts[i].Trim()) - 1;
                                                        selection_indexes.Add(index);
                                                    }
                                                    catch
                                                    {
                                                        // skip invalid index
                                                    }
                                                }
                                            }
                                            catch
                                            {
                                                selection_indexes.Add(0);
                                            }
                                        }
                                        break;
                                    case "TextZoomFactor":
                                        {
                                            try
                                            {
                                                m_text_zoom_factor = float.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                m_text_zoom_factor = DEFAULT_TEXT_ZOOM_FACTOR;
                                            }
                                        }
                                        break;
                                    case "Translator":
                                        {
                                            try
                                            {
                                                int index = int.Parse(parts[1].Trim());
                                                if (index < this.TranslatorComboBox.Items.Count)
                                                {
                                                    this.TranslatorComboBox.SelectedIndex = index;
                                                }
                                                else
                                                {
                                                    this.TranslatorComboBox.SelectedItem = -1;
                                                }
                                            }
                                            catch
                                            {
                                                if (this.TranslatorComboBox.Items.Count >= 3)
                                                {
                                                    this.TranslatorComboBox.SelectedItem = m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLATION].Name;
                                                }
                                                else
                                                {
                                                    this.TranslatorComboBox.SelectedItem = -1;
                                                }
                                            }
                                        }
                                        break;
                                    // [Audio]
                                    case "Volume":
                                        {
                                            try
                                            {
                                                m_audio_volume = int.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                m_audio_volume = DEFAULT_AUDIO_VOLUME;
                                            }
                                        }
                                        break;
                                    case "SilenceBetweenVerses":
                                        {
                                            try
                                            {
                                                m_silence_between_verses = float.Parse(parts[1].Trim());
                                            }
                                            catch
                                            {
                                                m_silence_between_verses = DEFAULT_SILENCE_BETWEEN_VERSES;
                                            }
                                        }
                                        break;
                                    case "Reciter":
                                        {
                                            try
                                            {
                                                int index = int.Parse(parts[1].Trim());
                                                if (index < this.RecitationsComboBox.Items.Count)
                                                {
                                                    this.RecitationsComboBox.SelectedIndex = index;
                                                }
                                                else
                                                {
                                                    this.RecitationsComboBox.SelectedItem = -1;
                                                }
                                            }
                                            catch
                                            {
                                                this.RecitationsComboBox.SelectedItem = m_client.Book.RecitationInfos[Client.DEFAULT_RECITATION].Reciter;
                                            }
                                        }
                                        break;
                                    case "TranslationUrlPrefix":
                                        {
                                            try
                                            {
                                                TranslationInfo.UrlPrefix = parts[1].Trim();
                                            }
                                            catch
                                            {
                                                TranslationInfo.UrlPrefix = TranslationInfo.DEFAULT_URL_PREFIX;
                                            }
                                        }
                                        break;
                                    case "TranslationFileType":
                                        {
                                            try
                                            {
                                                TranslationInfo.FileType = parts[1].Trim();
                                            }
                                            catch
                                            {
                                                TranslationInfo.FileType = TranslationInfo.DEFAULT_FILE_TYPE;
                                            }
                                        }
                                        break;
                                    case "TranslationIconUrlPrefix":
                                        {
                                            try
                                            {
                                                TranslationInfo.IconUrlPrefix = parts[1].Trim();
                                            }
                                            catch
                                            {
                                                TranslationInfo.IconUrlPrefix = TranslationInfo.DEFAULT_ICON_URL_PREFIX;
                                            }
                                        }
                                        break;
                                    case "RecitationUrlPrefix":
                                        {
                                            try
                                            {
                                                RecitationInfo.UrlPrefix = parts[1].Trim();
                                            }
                                            catch
                                            {
                                                RecitationInfo.UrlPrefix = RecitationInfo.DEFAULT_URL_PREFIX;
                                            }
                                        }
                                        break;
                                    case "RecitationFileType":
                                        {
                                            try
                                            {
                                                RecitationInfo.FileType = parts[1].Trim();
                                            }
                                            catch
                                            {
                                                RecitationInfo.FileType = RecitationInfo.DEFAULT_FILE_TYPE;
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                    }

                    m_client.Selection = new Selection(m_client.Book, selection_scope, selection_indexes);
                }
            }
            catch
            {
                // silence Parse exceptions
                // continue with next INI entry
            }
        }
        else // first Application launch
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Width = DEFAULT_WINDOW_WIDTH;
            this.Height = DEFAULT_WINDOW_HEIGHT;

            if (this.ChapterComboBox.Items.Count > 1)
            {
                this.ChapterComboBox.SelectedIndex = 0;
            }

            if (this.TranslatorComboBox.Items.Count >= 3)
            {
                this.TranslatorComboBox.SelectedItem = m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLATION].Name;
            }

            if (m_client != null)
            {
                try
                {
                    m_client.Selection = new Selection(m_client.Book, SelectionScope.Chapter, new List<int>() { 0 });
                }
                catch
                {
                    // log exception
                }
            }

            this.MainTextBox.SelectionStart = 0;
            this.MainTextBox.SelectionLength = 0;
        }
    }
    private void SaveApplicationOptions()
    {
        try
        {
            using (StreamWriter writer = new StreamWriter(m_ini_filename, false, Encoding.Unicode))
            {
                if (this.WindowState == FormWindowState.Maximized)
                {
                    this.WindowState = FormWindowState.Normal;
                }

                writer.WriteLine("[Window]");
                if (this.WindowState == FormWindowState.Minimized)
                {
                    // restore or width/height will be saved as 0
                    writer.WriteLine("Top=" + (Screen.PrimaryScreen.WorkingArea.Height - DEFAULT_WINDOW_HEIGHT) / 2);
                    writer.WriteLine("Left=" + (Screen.PrimaryScreen.WorkingArea.Width - DEFAULT_WINDOW_WIDTH) / 2);
                    writer.WriteLine("Width=" + DEFAULT_WINDOW_WIDTH);
                    writer.WriteLine("Height=" + DEFAULT_WINDOW_HEIGHT);
                    writer.WriteLine("TranslationBoxTop=" + DEFAULT_TRANSLATION_BOX_TOP);
                }
                else
                {
                    writer.WriteLine("Top=" + this.Top);
                    writer.WriteLine("Left=" + this.Left);
                    writer.WriteLine("Width=" + this.Width);
                    writer.WriteLine("Height=" + this.Height);
                    writer.WriteLine("TranslationBoxTop=" + m_translation_box_top);
                }
                writer.WriteLine();

                writer.WriteLine("[Text]");
                writer.WriteLine("WordWrap=" + this.MainTextBox.WordWrap);
                if (m_client != null)
                {
                    if (m_client.Selection != null)
                    {
                        writer.WriteLine("SelectionScope=" + (int)m_client.Selection.Scope);
                        StringBuilder str = new StringBuilder("SelectionIndexes=");
                        foreach (int index in m_client.Selection.Indexes)
                        {
                            str.Append((index + 1).ToString() + "+");
                        }
                        if (str.Length > 0) // remove last "+"
                        {
                            str.Remove(str.Length - 1, 1);
                        }
                        writer.WriteLine(str);
                    }
                }
                writer.WriteLine("TextZoomFactor=" + m_text_zoom_factor);
                writer.WriteLine("Translator=" + this.TranslatorComboBox.SelectedIndex);
                writer.WriteLine();

                writer.WriteLine("[Audio]");
                writer.WriteLine("Volume=" + m_audio_volume);
                writer.WriteLine("SilenceBetweenVerses=" + m_silence_between_verses);
                writer.WriteLine("Reciter=" + this.RecitationsComboBox.SelectedIndex);
                writer.WriteLine();

                writer.WriteLine("[Downloads]");
                writer.WriteLine("TranslationUrlPrefix=" + TranslationInfo.UrlPrefix);
                writer.WriteLine("TranslationFileType=" + TranslationInfo.FileType);
                writer.WriteLine("TranslationIconUrlPrefix=" + TranslationInfo.IconUrlPrefix);
                writer.WriteLine("RecitationUrlPrefix=" + RecitationInfo.UrlPrefix);
                writer.WriteLine("RecitationFileType=" + RecitationInfo.FileType);
            }
        }
        catch
        {
            // silence IO errors in case running from read-only media (CD/DVD)
        }
    }
    private void InitializeControls()
    {
        if (BookmarkTextBox.Text.Length > 0)
        {
            m_note_writing_instruction = BookmarkTextBox.Text;
        }

        // use Right-Click for going to Related Words instead of shwoing context menu
        RegisterContextMenu(MainTextBox);
        RegisterContextMenu(TranslationTextBox);
        MainTextBox.ReadOnly = true;

        PageNumericUpDown.Minimum = Page.MIN_NUMBER;
        PageNumericUpDown.Maximum = Page.MAX_NUMBER;
        StationNumericUpDown.Minimum = Station.MIN_NUMBER;
        StationNumericUpDown.Maximum = Station.MAX_NUMBER;
        PartNumericUpDown.Minimum = Part.MIN_NUMBER;
        PartNumericUpDown.Maximum = Part.MAX_NUMBER;
        GroupNumericUpDown.Minimum = Model.Group.MIN_NUMBER;
        GroupNumericUpDown.Maximum = Model.Group.MAX_NUMBER;
        QuarterNumericUpDown.Minimum = Quarter.MIN_NUMBER;
        QuarterNumericUpDown.Maximum = Quarter.MAX_NUMBER;
        BowingNumericUpDown.Minimum = Bowing.MIN_NUMBER;
        BowingNumericUpDown.Maximum = Bowing.MAX_NUMBER;
        PageNumericUpDown.Minimum = Page.MIN_NUMBER;
        PageNumericUpDown.Maximum = Page.MAX_NUMBER;

        // install default size font
        SetFontSize(m_font_size);

        SetupToolTips();
    }
    private void SetupToolTips()
    {
        this.ToolTip.SetToolTip(this.WebsiteLinkLabel, "اللهُمَّ صَلِّ على مُحَمَّدٍ وءالِ مُحَمَّدٍ");
        this.ToolTip.SetToolTip(this.VersionLabel, "About");
        this.ToolTip.SetToolTip(this.PlayerPreviousLabel, "Previous verse");
        this.ToolTip.SetToolTip(this.PlayerPlayLabel, "Play");
        this.ToolTip.SetToolTip(this.PlayerNextLabel, "Next verse");
        this.ToolTip.SetToolTip(this.PlayerStopLabel, "Stop");
        this.ToolTip.SetToolTip(this.PlayerRepeatLabel, "Repeat verse");
        this.ToolTip.SetToolTip(this.PlayerRepeatSelectionLabel, "Repeat selection");
        this.ToolTip.SetToolTip(this.PlayerMuteLabel, "Mute");
        this.ToolTip.SetToolTip(this.PlayerSilenceTrackBar, "Silence between verses");
        this.ToolTip.SetToolTip(this.ChapterComboBox, "CC, CC:VV, CC-CC, CC:VV-CC, CC-CC:VV, CC:VV-CC:VV");        // 11, 13-14, 15:55, 16:19-23, 13-14:19, 24:35-27:62
        this.ToolTip.SetToolTip(this.ChapterVerseNumericUpDown, "ءاية");
        this.ToolTip.SetToolTip(this.PartNumericUpDown, "جزء");
        this.ToolTip.SetToolTip(this.PageNumericUpDown, "صفحة");
        this.ToolTip.SetToolTip(this.StationNumericUpDown, "منزل");
        this.ToolTip.SetToolTip(this.GroupNumericUpDown, "حزب");
        this.ToolTip.SetToolTip(this.QuarterNumericUpDown, "ربع حزب");
        this.ToolTip.SetToolTip(this.BowingNumericUpDown, "ركوع");
    }

    private ContextMenu EditContextMenu;
    private MenuItem EditUndoMenuItem;
    private MenuItem EditCutMenuItem;
    private MenuItem EditCopyMenuItem;
    private MenuItem EditPasteMenuItem;
    private MenuItem EditCopyAllMenuItem;
    private MenuItem Separator1MenuItem;
    private MenuItem EditSelectAllMenuItem;
    private MenuItem FindExactMatchMenuItem;
    private MenuItem FindSimilarWordsMenuItem;
    private MenuItem FindRelatedWordsMenuItem;
    private MenuItem Separator2MenuItem;
    private MenuItem GotoVerseMenuItem;
    private void RegisterContextMenu(TextBoxBase control)
    {
        EditContextMenu = new ContextMenu();
        MenuItem MenuItem = null;

        if (control != MainTextBox)
        {
            MenuItem = new MenuItem("Undo\t\tCtrl+Z");
            MenuItem.Click += new EventHandler(MenuItem_Undo);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditUndoMenuItem = MenuItem;

            MenuItem = new MenuItem("-");
            EditContextMenu.MenuItems.Add(MenuItem);

            MenuItem = new MenuItem("Cut\t\tCtrl+X");
            MenuItem.Click += new EventHandler(MenuItem_Cut);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditCutMenuItem = MenuItem;

            MenuItem = new MenuItem("Copy\t\tCtrl+C");
            MenuItem.Click += new EventHandler(MenuItem_Copy);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditCopyMenuItem = MenuItem;

            MenuItem = new MenuItem("Paste\t\tCtrl+V");
            MenuItem.Click += new EventHandler(MenuItem_Paste);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditPasteMenuItem = MenuItem;

            MenuItem = new MenuItem("-");
            EditContextMenu.MenuItems.Add(MenuItem);

            MenuItem = new MenuItem("Select All\tCtrl+A");
            MenuItem.Click += new EventHandler(MenuItem_SelectAll);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditSelectAllMenuItem = MenuItem;
        }
        else
        {
            MenuItem = new MenuItem("Copy All\t\tCtrl+C");
            MenuItem.Click += new EventHandler(MenuItem_Copy);
            EditContextMenu.MenuItems.Add(MenuItem);
            EditCopyAllMenuItem = MenuItem;

            MenuItem = new MenuItem("-");
            EditContextMenu.MenuItems.Add(MenuItem);
            Separator1MenuItem = MenuItem;

            MenuItem = new MenuItem("Exact Match\tF5");
            MenuItem.Click += new EventHandler(MenuItem_ExactMatch);
            EditContextMenu.MenuItems.Add(MenuItem);
            FindExactMatchMenuItem = MenuItem;

            MenuItem = new MenuItem("Similar Words\tF6");
            MenuItem.Click += new EventHandler(MenuItem_SimilarWords);
            EditContextMenu.MenuItems.Add(MenuItem);
            FindSimilarWordsMenuItem = MenuItem;

            MenuItem = new MenuItem("Related Words\tF7");
            MenuItem.Click += new EventHandler(MenuItem_RelatedWords);
            EditContextMenu.MenuItems.Add(MenuItem);
            FindRelatedWordsMenuItem = MenuItem;

            MenuItem = new MenuItem("-");
            EditContextMenu.MenuItems.Add(MenuItem);
            Separator2MenuItem = MenuItem;

            MenuItem = new MenuItem("Goto Verse\tF10");
            MenuItem.Click += new EventHandler(MenuItem_GotoVerse);
            EditContextMenu.MenuItems.Add(MenuItem);
            GotoVerseMenuItem = MenuItem;
        }

        EditContextMenu.Popup += new EventHandler(ContextMenu_Popup);
        EditContextMenu.Collapse += new EventHandler(ContextMenu_Collapse);

        control.ContextMenu = EditContextMenu;
    }
    private void ContextMenu_Popup(object sender, EventArgs e)
    {
        if (MainTextBox.SelectionLength == 0)
        {
            EditCopyAllMenuItem.Text = "Copy All\t\tCtrl+C";
        }
        else
        {
            EditCopyAllMenuItem.Text = "Copy\t\tCtrl+C";
        }

        Separator2MenuItem.Visible = m_found_verses_displayed;
        GotoVerseMenuItem.Visible = m_found_verses_displayed;

        //if (sender is ContextMenu)
        //{
        //    if ((sender as ContextMenu).SourceControl is TextBoxBase)
        //    {
        //        ((sender as ContextMenu).SourceControl as TextBoxBase).Cursor = Cursors.Arrow;
        //    }
        //}
    }
    private void ContextMenu_Collapse(object sender, EventArgs e)
    {
        //if (sender is ContextMenu)
        //{
        //    if ((sender as ContextMenu).SourceControl is TextBoxBase)
        //    {
        //        ((sender as ContextMenu).SourceControl as TextBoxBase).Cursor = Cursors.Default;
        //    }
        //}
    }
    private void MenuItem_Undo(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl is TextBoxBase)
                {
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).Undo();
                }
            }
        }
    }
    private void MenuItem_Cut(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl is TextBoxBase)
                {
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).Cut();
                }
            }
        }
    }
    private void MenuItem_Copy(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl is TextBoxBase)
                {
                    TextBoxBase control = (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase);
                    bool nothing_selected = false;
                    if (control.SelectionLength == 0)
                    {
                        nothing_selected = true;
                        control.SelectAll();
                    }
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).Copy();
                    if (nothing_selected)
                    {
                        control.DeselectAll();
                    }
                }
            }
        }
    }
    private void MenuItem_Paste(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl is TextBoxBase)
                {
                    Thread.Sleep(100); // must give chance for Clipboard to refresh its content before Paste
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).Paste();
                }
            }
        }
    }
    private void MenuItem_SelectAll(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl is TextBoxBase)
                {
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).SelectAll();
                    (((sender as MenuItem).Parent as ContextMenu).SourceControl as TextBoxBase).KeyDown += new KeyEventHandler(TextBox_KeyDown);
                }
            }
        }
    }
    private void MenuItem_ExactMatch(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl == MainTextBox)
                {
                    DoFindExactMatch(((sender as MenuItem).Parent as ContextMenu).SourceControl);
                }
            }
        }
    }
    private void MenuItem_SimilarWords(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl == MainTextBox)
                {
                    DoFindSimilarWords(((sender as MenuItem).Parent as ContextMenu).SourceControl);
                }
            }
        }
    }
    private void MenuItem_RelatedWords(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl == MainTextBox)
                {
                    DoFindRelatedWords(((sender as MenuItem).Parent as ContextMenu).SourceControl);
                }
            }
        }
    }
    private void MenuItem_GotoVerse(object sender, EventArgs e)
    {
        if (sender is MenuItem)
        {
            if ((sender as MenuItem).Parent is ContextMenu)
            {
                if (((sender as MenuItem).Parent as ContextMenu).SourceControl == MainTextBox)
                {
                    DoGotoVerse();
                }
            }
        }
    }
    private void DoFindExactMatch(object sender)
    {
        if (m_client != null)
        {
            if (sender is TextBoxBase)
            {
                string text = (sender as TextBoxBase).SelectedText.Trim();
                if (text.Length == 0)
                {
                    Word current_word = GetWordAtCursor();
                    if (current_word == null)
                    {
                        return;
                    }
                    text = current_word.Text;
                }
                text = RemovePunctuationMarks(text);

                if (!String.IsNullOrEmpty(text))
                {
                    FindByTextLanguageType language_type = FindByTextLanguageType.Arabic;

                    string translation = Client.DEFAULT_TRANSLATION;
                    if (TranslatorComboBox.SelectedItem != null)
                    {
                        translation = m_client.GetTranslationKey(TranslatorComboBox.SelectedItem.ToString());
                    }

                    FindByTextLocation text_location = FindByTextLocation.Anywhere;
                    bool case_sensitive = false;
                    FindByTextWordness wordness = FindByTextWordness.Any;
                    int multiplicity = -1;
                    FindByText(text, language_type, translation, text_location, case_sensitive, wordness, multiplicity, true);
                }
            }
        }
    }
    private void DoFindSimilarWords(object sender)
    {
        if (m_client != null)
        {
            if (sender is TextBoxBase)
            {
                string text = (sender as TextBoxBase).SelectedText.Trim();
                if (text.Length == 0) // no selection, get word under mouse pointer
                {
                    Word current_word = GetWordAtCursor();
                    if (current_word == null)
                    {
                        return;
                    }
                    text = current_word.Text;
                }

                DoFindSimilarWords(text);
            }
        }
    }
    private void DoFindSimilarWords(string text)
    {
        this.Cursor = Cursors.WaitCursor;
        try
        {
            if (m_client != null)
            {
                PrepareNewSearch();

                double similarity_percentage = 0.75D;
                FindBySimilarityMethod find_by_similarity_method = FindBySimilarityMethod.SimilarWords;

                m_client.FindPhrases(text, similarity_percentage);
                if (m_client.FoundPhrases != null)
                {
                    string similarity_source = " to " + text + " ";
                    int matches = m_client.FoundPhrases.Count;
                    m_find_result_header = m_client.FoundVerses.Count + ((m_client.FoundVerses.Count == 1) ? " verse" : " verses") + " with " + find_by_similarity_method.ToString() + similarity_source + " in " + "Entire Book";

                    DisplayFoundVerses(true, false);
                }
            }
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void DoFindRelatedWords(object sender)
    {
        if (m_client != null)
        {
            if (sender is TextBoxBase)
            {
                string text = (sender as TextBoxBase).SelectedText.Trim();
                if (text.Length == 0)
                {
                    Word current_word = GetWordAtCursor();
                    if (current_word == null)
                    {
                        return;
                    }
                    text = current_word.Text;
                }
                text = RemovePunctuationMarks(text);

                // if a whole word, search by root
                if ((text.Length > 0) && (!text.Contains(" ")) && (!text.Contains("\t")))
                {
                    int multiplicity = -1;
                    FindByRoot(text, multiplicity);
                }
            }
        }
    }
    private bool m_found_verses_displayed = false;
    private void DoGotoVerse()
    {
        if (m_client != null)
        {
            // go to double_click_target (Chapter or Page) containing double clicked verse
            if (m_found_verses_displayed)
            {
                Verse verse = GetCurrentVerse();
                if (verse != null)
                {
                    if (verse.Chapter != null)
                    {
                        if (m_client.Selection != null)
                        {
                            m_client.Selection = new Selection(m_client.Book, SelectionScope.Chapter, new List<int>() { verse.Chapter.Number - 1 });

                            DisplaySelection(false);

                            // move cursor to double_clicked verse
                            List<Verse> verses = m_client.Selection.Verses;
                            if (verses != null)
                            {
                                if (verses.Count > 0)
                                {
                                    int verses_to_skip = verse.Number - verses[0].Number;
                                    if (verses.Count > verses_to_skip)
                                    {
                                        int char_index = 0;
                                        if (MainTextBox.WordWrap)
                                        {
                                            for (int i = 0; i < verses_to_skip; i++)
                                            {
                                                char_index += verses[i].Text.Length + verse.Endmark.Length;
                                            }
                                        }
                                        else
                                        {
                                            for (int i = 0; i < verses_to_skip; i++)
                                            {
                                                char_index += verses[i].Text.Length + 1; // 1 for "\n"
                                            }
                                        }
                                        MainTextBox.SelectionStart = char_index;
                                        MainTextBox.Focus();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private float m_text_zoom_factor = DEFAULT_TEXT_ZOOM_FACTOR;
    private float m_min_zoom_factor = 0.1F;
    private float m_max_zoom_factor = 2.0F;
    private float m_zoom_factor_increment = 0.1F;
    private float m_error_margin = 0.001F;
    private void MainTextBox_KeyDown(object sender, KeyEventArgs e)
    {
        try
        {
            if ((e.Control) && (e.KeyCode == Keys.V))
            {
                Thread.Sleep(100); // must give chance for Clipboard to refresh its content before Paste
                MainTextBox.Paste();
                e.Handled = true;
            }
        }
        finally
        {
            ToolTip.SetToolTip(MainTextBox, null);
            UpdateMainTextBoxCursor();
        }
    }
    private void MainTextBox_KeyUp(object sender, KeyEventArgs e)
    {
        try
        {
            bool NavigationKeys = (
            e.KeyCode == Keys.Up ||
            e.KeyCode == Keys.Right ||
            e.KeyCode == Keys.Down ||
            e.KeyCode == Keys.Left ||
            e.KeyCode == Keys.Home ||
            e.KeyCode == Keys.End);

            if (NavigationKeys)
            {
                PrepareVerseToPlay();
            }
        }
        finally
        {
            ToolTip.SetToolTip(MainTextBox, null);
            UpdateMainTextBoxCursor();
        }
    }
    private void MainTextBox_Enter(object sender, EventArgs e)
    {
        this.AcceptButton = null;
    }
    private void MainTextBox_MouseEnter(object sender, EventArgs e)
    {
        UpdateMainTextBoxCursor();
    }
    private void MainTextBox_SelectionChanged(object sender, EventArgs e)
    {
        if (
             (sender == MainTextBox) &&
             (
               (MainTextBox.Focused)
             )
           )
        {
            if (m_client != null)
            {
                m_is_selection_mode = false;
                DisplayCurrentPositions();
            }
        }
    }
    private bool m_mouse_down = false;
    private bool m_dragging = false;
    private Point m_previous_location = new Point(0, 0);
    private void MainTextBox_MouseDown(object sender, MouseEventArgs e)
    {
        // set cursor at mouse click location so we know which word to get related words for
        RichTextBox control = (sender as RichTextBox);
        int start = control.GetCharIndexFromPosition(e.Location);
        if (
             (start <= control.SelectionStart)
             ||
             (start > (control.SelectionStart + control.SelectionLength))
           )
        {
            control.SelectionStart = start;
            control.SelectionLength = 0;
        }

        m_mouse_down = true;
        m_dragging = false;
        UpdateMainTextBoxCursor();
    }
    private void MainTextBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (ModifierKeys == Keys.None)
        {
            // start dragging if mouse is down and no key is down
            m_dragging = m_mouse_down;
            UpdateMainTextBoxCursor();

            // stop flickering
            if (
                (Math.Abs(m_previous_location.X - e.X) < 4)
                &&
                (Math.Abs(m_previous_location.Y - e.Y) < 4)
               )
            {
                return;
            }
            m_previous_location = e.Location;

            try
            {
                if (m_client != null)
                {
                    Word word = GetWordAtPointer(e);
                    if (word != null)
                    {
                        string root = word.Text;
                        string related_words_lines = "";
                        int words_per_line = 0;
                        int max_words_per_line = 10;
                        List<string> related_words = m_client.Book.GetRelatedWords(root);
                        if (related_words != null)
                        {
                            StringBuilder str = new StringBuilder();
                            foreach (string related_word in related_words)
                            {
                                words_per_line++;
                                str.Append(related_word + (((words_per_line % max_words_per_line) == 0) ? "\r\n" : "\t"));
                            }
                            related_words_lines = str.ToString();
                        }

                        ToolTip.SetToolTip
                        (
                             MainTextBox,
                             word.Address + "        " +
                             word.Transliteration + "        " +
                             word.Text + "        " +
                             word.Meaning + "        " +
                             word.Occurrence.ToString() + "/" + word.Occurrences.ToString() + "\r\n" +
                             related_words_lines
                        );
                    }
                    else
                    {
                        ToolTip.SetToolTip(MainTextBox, null);
                    }
                }
            }
            catch  /*(Exception ex)*/
            {
                // reset dragging in case of any error
                m_dragging = false;
                UpdateMainTextBoxCursor();
            }
        }
    }
    private void MainTextBox_MouseUp(object sender, MouseEventArgs e)
    {
        try
        {
            MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
            MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
            MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);

            if (m_dragging)
            {
                // prepare to play verse
                PrepareVerseToPlay();
            }
            else
            {
                if (MouseButtons != MouseButtons.Right)
                {
                    // movement was < 4 pixels
                    // go to related words to word under mouse pointer
                    DoFindRelatedWords(sender);
                }
            }
        }
        finally
        {
            m_mouse_down = false;
            m_dragging = false;
            UpdateMainTextBoxCursor();

            MainTextBox.SelectionChanged += new EventHandler(MainTextBox_SelectionChanged);
        }
    }
    private void UpdateMainTextBoxCursor()
    {
        if (m_dragging)
        {
            // stop cursor flicker
            if (MainTextBox.Cursor != Cursors.IBeam)
            {
                MainTextBox.Cursor = Cursors.IBeam;
            }
        }
        else
        {
            // stop cursor flicker
            if (MainTextBox.Cursor != Cursors.Hand)
            {
                MainTextBox.Cursor = Cursors.Hand;
            }
        }
    }
    private void MainTextBox_MouseWheel(object sender, MouseEventArgs e)
    {
        if (ModifierKeys == Keys.Control)
        {
            ZoomOutLabel.Enabled = true;
            ZoomInLabel.Enabled = true;
            if (MainTextBox.ZoomFactor <= (m_min_zoom_factor + m_error_margin))
            {
                MainTextBox.ZoomFactor = m_min_zoom_factor;
                ZoomOutLabel.Enabled = false;
                ZoomInLabel.Enabled = true;
            }
            else if (MainTextBox.ZoomFactor >= (m_max_zoom_factor - m_error_margin))
            {
                MainTextBox.ZoomFactor = m_max_zoom_factor;
                ZoomOutLabel.Enabled = true;
                ZoomInLabel.Enabled = false;
            }
            m_text_zoom_factor = MainTextBox.ZoomFactor;
        }
    }
    private void ZoomInLabel_Click(object sender, EventArgs e)
    {
        if (m_text_zoom_factor <= (m_max_zoom_factor - m_zoom_factor_increment + m_error_margin))
        {
            m_text_zoom_factor += m_zoom_factor_increment;
            MainTextBox.ZoomFactor = m_text_zoom_factor;
        }
        // re-check same condition after zoom_factor update
        ZoomInLabel.Enabled = (m_text_zoom_factor <= (m_max_zoom_factor - m_zoom_factor_increment + m_error_margin));
        ZoomOutLabel.Enabled = true;
    }
    private void ZoomOutLabel_Click(object sender, EventArgs e)
    {
        if (m_text_zoom_factor >= (m_min_zoom_factor + m_zoom_factor_increment - m_error_margin))
        {
            m_text_zoom_factor -= m_zoom_factor_increment;
            MainTextBox.ZoomFactor = m_text_zoom_factor;
        }
        // re-check same condition after zoom_factor update
        ZoomOutLabel.Enabled = (m_text_zoom_factor >= (m_min_zoom_factor + m_zoom_factor_increment - m_error_margin));
        ZoomInLabel.Enabled = true;
    }
    private void WordWrapLabel_Click(object sender, EventArgs e)
    {
        MainTextBox_ToggleWordWrap(); // add/remove Verse.EndMark, wrap/unwrap and redisplay
    }
    private void MainTextBox_ToggleWordWrap() // F11
    {
        MainTextBox.WordWrap = !MainTextBox.WordWrap;
        if (MainTextBox.WordWrap)
        {
            Verse.IncludeNumber = true;
            TranslationTextBox.WordWrap = true;

            if (m_mp3player.Playing)
            {
                PlayerStopLabel_Click(null, null);
            }
            RecitationGroupBox.Enabled = false;
        }
        else
        {
            Verse.IncludeNumber = false;
            TranslationTextBox.WordWrap = false;
            RecitationGroupBox.Enabled = true;
        }

        if (m_found_verses_displayed)
        {
            DisplayFoundVerses(false, false);
        }
        else
        {
            DisplaySelection(false);
        }
    }

    private string m_note_writing_instruction = "write a note";
    private Color m_note_writing_instruction_color = Color.Gray;
    private Color m_note_edit_color = Color.Black;
    private Color m_note_view_color = Color.Blue;
    private void BookmarkTextBox_Enter(object sender, EventArgs e)
    {
        BookmarkTextBox.ForeColor = m_note_edit_color;
        if (BookmarkTextBox.Text.StartsWith(m_note_writing_instruction))
        {
            BookmarkTextBox.Text = "";
        }
    }
    private void BookmarkTextBox_Leave(object sender, EventArgs e)
    {
        if (BookmarkTextBox.Text.Length == 0)
        {
            DisplayNoteWritingInstruction();
        }
        else
        {
            AddBookmarkButton_Click(sender, null);
        }
        this.AcceptButton = null;
    }
    private void BookmarkTextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Enter)
        {
            if (BookmarkTextBox.Text.Length > 0)
            {
                AddBookmarkButton_Click(sender, null);
            }
            else
            {
                DeleteBookmarkButton_Click(sender, null);
            }
        }
        else
        {
            BookmarkTextBox.ForeColor = m_note_edit_color;
        }
        UpdateBookmarkHistoryButtons();
    }
    private void DisplayNoteWritingInstruction()
    {
        DeleteBookmarkButton.Enabled = false;
        ClearBookmarksButton.Enabled = false;

        BookmarkTextBox.ForeColor = m_note_writing_instruction_color;
        if (BookmarkTextBox.Focused)
        {
            BookmarkTextBox.Text = "";
        }
        else
        {
            if (m_client != null)
            {
                if (m_client.Selection != null)
                {
                    if (m_client.Book != null)
                    {
                        if (m_client.Selection.Scope == SelectionScope.Book)
                        {
                            BookmarkTextBox.Text = m_note_writing_instruction + " for "
                                + m_client.Selection.Scope.ToString();
                        }
                        else if (m_client.Selection.Scope == SelectionScope.Verse)
                        {
                            BookmarkTextBox.Text = m_note_writing_instruction + " for Chapter "
                                + (ChapterComboBox.SelectedIndex + 1).ToString() + " Verse "
                                + (ChapterVerseNumericUpDown.Value).ToString();
                        }
                        else
                        {
                            StringBuilder str = new StringBuilder();
                            foreach (int index in m_client.Selection.Indexes)
                            {
                                str.Append((index + 1).ToString() + "+");
                            }
                            if (str.Length > 0)
                            {
                                str.Remove(str.Length - 1, 1);
                            }

                            BookmarkTextBox.Text = m_note_writing_instruction + " for "
                                         + m_client.Selection.Scope.ToString() + " "
                                         + str.ToString();

                            ToolTip.SetToolTip(BookmarkTextBox, null);
                        }
                    }
                }
            }
        }
        UpdateBookmarkHistoryButtons();
    }
    private void DisplayNote(Bookmark bookmark)
    {
        if (m_client != null)
        {
            if (bookmark != null)
            {
                if (bookmark.Selection != null)
                {
                    BookmarkTextBox.Text = bookmark.Note;
                    BookmarkTextBox.ForeColor = m_note_view_color;

                    string hint = "Creation Time" + "\t" + bookmark.CreatedTime + "\r\n"
                         + "Last Modified" + "\t" + bookmark.LastModifiedTime;
                    ToolTip.SetToolTip(BookmarkTextBox, hint);
                }
            }
            else
            {
                DisplayNoteWritingInstruction();
            }
        }
    }
    private void DisplayBookmark(Bookmark bookmark)
    {
        if (bookmark != null)
        {
            if (bookmark.Selection != null)
            {
                if (m_client != null)
                {
                    m_client.Selection = new Selection(m_client.Book, bookmark.Selection.Scope, bookmark.Selection.Indexes);

                    DisplaySelection(false);

                    BookmarkTextBox.Text = bookmark.Note;
                    BookmarkTextBox.ForeColor = m_note_view_color;
                    string hint = "Creation Time" + "\t" + bookmark.CreatedTime + "\r\n"
                         + "Last Modified" + "\t" + bookmark.LastModifiedTime;
                    ToolTip.SetToolTip(BookmarkTextBox, hint);
                    MainTextBox.Focus();

                    UpdateBookmarkHistoryButtons();
                }
            }
        }
    }
    private void AddBookmarkButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_client.Book != null)
                {
                    if (BookmarkTextBox.Text.StartsWith(m_note_writing_instruction))
                    {
                        // ignore it
                    }
                    else if (BookmarkTextBox.Text.Length == 0)
                    {
                        DeleteBookmarkButton_Click(sender, null);
                    }
                    else //if (!BookmarkTextBox.Text.StartsWith(m_note_writing_instruction))
                    {
                        Selection selection = new Selection(m_client.Book, m_client.Selection.Scope, m_client.Selection.Indexes);
                        Bookmark bookmark = m_client.AddOverwriteBookmark(selection, BookmarkTextBox.Text);

                        BookmarkTextBox.ForeColor = m_note_view_color;
                        UpdateBookmarkHistoryButtons();
                    }
                }
            }
        }
    }
    private void PreviousBookmarkButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                Bookmark bookmark = m_client.GotoPreviousBookmark();
                if (bookmark != null)
                {
                    DisplayBookmark(bookmark);
                }
            }
        }
    }
    private void NextBookmarkButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                Bookmark bookmark = m_client.GotoNextBookmark();
                if (bookmark != null)
                {
                    DisplayBookmark(bookmark);
                }
            }
        }
    }
    private void BookmarkCounterLabel_Click(object sender, EventArgs e)
    {
        if (m_client.Bookmarks.Count > 0)
        {
            DisplayBookmark(m_client.CurrentBookmark);
        }
    }
    private void DeleteBookmarkButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                // remove existing bookmark (if any)
                m_client.DeleteCurrentBookmark();

                Bookmark bookmark = m_client.CurrentBookmark;
                if (bookmark != null)
                {
                    DisplayBookmark(bookmark);
                }
                else
                {
                    DisplaySelection(false);
                }
            }
        }
    }
    private void ClearBookmarksButton_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show(
            "Delete all bookmarks and notes?",
            Application.ProductName,
            MessageBoxButtons.YesNo,
            MessageBoxIcon.Question) == DialogResult.Yes)
        {
            if (m_client != null)
            {
                if (m_client.Book != null)
                {
                    m_client.ClearBookmarks();
                    DisplaySelection(false);
                }
            }
        }
    }
    private void UpdateBookmarkHistoryButtons()
    {
        if (m_client != null)
        {
            if (m_client.Bookmarks != null)
            {
                {
                    PreviousBookmarkButton.Enabled = (m_client.Bookmarks.Count > 0) && (m_client.CurrentBookmarkIndex > 0);
                    NextBookmarkButton.Enabled = (m_client.Bookmarks.Count > 0) && (m_client.CurrentBookmarkIndex < m_client.Bookmarks.Count - 1);
                    BookmarkCounterLabel.Text = (m_client.CurrentBookmarkIndex + 1).ToString() + " / " + m_client.Bookmarks.Count.ToString();
                    DeleteBookmarkButton.Enabled = (!BookmarkTextBox.Text.StartsWith(m_note_writing_instruction)) && (!m_found_verses_displayed) && (m_client.Bookmarks.Count > 0);
                    ClearBookmarksButton.Enabled = (!BookmarkTextBox.Text.StartsWith(m_note_writing_instruction)) && (!m_found_verses_displayed) && (m_client.Bookmarks.Count > 0);
                    ClearBookmarksButton.BackColor = (!BookmarkTextBox.Text.StartsWith(m_note_writing_instruction)) && (!m_found_verses_displayed) && (m_client.Bookmarks.Count > 0) ? Color.LightCoral : SystemColors.ControlLight;
                }
            }
        }
    }

    private string m_recitation_folder = Client.DEFAULT_RECITATION;
    private MP3Player m_mp3player = new MP3Player();
    private int m_audio_volume = DEFAULT_AUDIO_VOLUME;
    private string m_downloaded_audio_filename = "";
    private bool m_playerLooping = false;
    private bool m_playerLoopingAll = false;
    private bool m_first_play = true;

    private bool m_in_silent_mode = false;
    private float m_silence_between_verses = DEFAULT_SILENCE_BETWEEN_VERSES; // in multiples of verses
    private int m_silence_time_between_verses = 0;
    private void PrepareVerseToPlay()
    {
        if (m_mp3player != null)
        {
            if (m_mp3player.Opened)
            {
                // prepare to play this verse, not next
                if (m_found_verses_displayed)
                {
                    if (m_found_verses_current_line_index >= 0)
                    {
                        m_found_verses_current_line_index--;
                    }
                }
                else
                {
                    if (m_current_line_index >= 0)
                    {
                        m_current_line_index--;
                    }
                }
            }
        }
    }
    private void PlayNextVerse()
    {
        // if looping then replay
        if (m_playerLooping)
        {
            PlayerPlayLabel_Click(null, null);
        }
        else // move to next verse
        {
            if (GotoNextLine())
            {
                PlayerPlayLabel_Click(null, null);
            }
            else // if final verse in selection
            {
                PlayerStopLabel_Click(null, null);

                // reset to the top or the first page image
                m_current_line_index = 0;
                m_found_verses_current_line_index = 0;
                if (m_found_verses_displayed)
                {
                    DisplayFoundVerses(false, false);
                    if (m_client != null)
                    {
                        DisplayTranslation(m_client.FoundVerses[0]);
                    }
                }
                else
                {
                    DisplaySelection(false);
                    if (m_client != null)
                    {
                        if (m_client.Selection != null)
                        {
                            DisplayTranslation(m_client.Selection.Verses[0]);
                        }
                    }
                }
                m_is_selection_mode = false;

                if (m_playerLoopingAll)
                {
                    PlayerPlayLabel_Click(null, null);
                }
            }
        }
    }
    private void PlayerTimer_Tick(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            // if silent_mode or verse play is finished, then stop it
            if (
                    m_in_silent_mode
                    ||
                    ((m_mp3player.Length - m_mp3player.Position) < ((ulong)PlayerTimer.Interval / 2))
               )
            {
                // get verse time length before stop
                int verse_time_length = (int)m_mp3player.Length;

                // stop verse play
                if (m_mp3player.Opened)
                {
                    m_mp3player.Stop();
                    m_mp3player.Close();
                }

                // re-calculate required silence time
                m_silence_time_between_verses = (int)(verse_time_length * m_silence_between_verses);

                // if silence still required
                if (m_silence_time_between_verses > 0)
                {
                    m_in_silent_mode = true;
                    PlayerTimer.Interval = m_silence_time_between_verses;
                    return; // and call us back after Interval
                }

                m_in_silent_mode = false;
                PlayerTimer.Interval = 100;
                PlayNextVerse();
            }
        }
    }
    private void PlayerPlayAudhuBillah()
    {
        Verse audhuthuBillah_verse = null;
        if (DownloadVerseAudioFile(audhuthuBillah_verse))
        {
            m_mp3player.Open(m_downloaded_audio_filename);
        }
        else
        {
            m_mp3player.Open("Audio/audhubillah.mp3");
        }

        if (m_mp3player.Opened)
        {
            if (File.Exists("Images/player_pause.png"))
            {
                PlayerPlayLabel.Image = new Bitmap("Images/player_pause.png");
            }
            PlayerPlayLabel.Refresh();

            m_mp3player.VolumeAll = m_audio_volume;
            m_mp3player.Play();
        }
        else
        {
            PlayerStopLabel_Click(null, null);
            AskUserToDownloadAudioFilesManually();
        }
    }
    private void PlayerPlayBismAllah()
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                Chapter al_fatiha = null;
                foreach (Chapter chapter in m_client.Book.Chapters)
                {
                    if (chapter.Number == 1)
                    {
                        al_fatiha = chapter;
                        break;
                    }
                }

                if (al_fatiha != null)
                {
                    if (al_fatiha.Verses.Count > 0)
                    {
                        // download file if not on disk
                        if (DownloadVerseAudioFile(al_fatiha.Verses[0]))
                        {
                            m_mp3player.Open(m_downloaded_audio_filename);

                            if (m_mp3player.Opened)
                            {
                                if (File.Exists("Images/player_pause.png"))
                                {
                                    PlayerPlayLabel.Image = new Bitmap("Images/player_pause.png");
                                }
                                PlayerPlayLabel.Refresh();

                                m_mp3player.VolumeAll = m_audio_volume;
                                m_mp3player.Play();
                            }
                        }
                        else
                        {
                            PlayerStopLabel_Click(null, null);
                            AskUserToDownloadAudioFilesManually();
                        }
                    }
                }
            }
        }
    }
    private void PlayerOpenAudioFile(Verse verse)
    {
        if (verse != null)
        {
            if (m_mp3player != null)
            {
                try
                {
                    // on first play
                    if (m_first_play)
                    {
                        PlayerPlayAudhuBillah();
                        WaitForPlayToFinish();

                        // don't play bismAllah for not first verses NOR first verse of chapter 9 
                        if (verse.Chapter != null)
                        {
                            if ((verse.Chapter.Number != 9) && (verse.NumberInChapter != 1))
                            {
                                PlayerPlayBismAllah();
                                WaitForPlayToFinish();
                            }
                        }

                        m_first_play = false;
                    }

                    // on all plays
                    // play BismAllah for every verse 1, except chapter 9
                    if (verse.NumberInChapter == 1)
                    {
                        if (verse.Chapter != null)
                        {
                            if ((verse.Chapter.Number != 1) && (verse.Chapter.Number != 9))
                            {
                                PlayerPlayBismAllah();
                                WaitForPlayToFinish();
                            }
                        }
                    }

                    // download file if not on disk
                    if (DownloadVerseAudioFile(verse))
                    {
                        // open only, don't play
                        m_mp3player.Open(m_downloaded_audio_filename);
                    }
                    else
                    {
                        PlayerStopLabel_Click(null, null);
                        AskUserToDownloadAudioFilesManually();
                    }
                }
                catch
                {
                    PlayerStopLabel_Click(null, null);
                }
            }
        }
        else // invalid verse
        {
            MessageBox.Show("No verse available.", Application.ProductName);

            // reset player buttons
            PlayerStopLabel_Click(null, null);
        }
    }
    private void PlayerPreviousLabel_Click(object sender, EventArgs e)
    {
        int line_index = GetCurrentLineIndex() - 1;
        if (line_index >= 0)
        {
            bool player_is_opened = false;
            if (m_mp3player != null)
            {
                player_is_opened = m_mp3player.Opened;
                PlayerStopLabel_Click(null, null);
            }

            if (m_found_verses_displayed)
            {
                m_found_verses_current_line_index = line_index;
            }
            else
            {
                m_current_line_index = line_index;
            }
            GotoLine(line_index);

            if (m_mp3player != null)
            {
                if (player_is_opened)
                {
                    PlayerPlayLabel_Click(null, null);
                }
            }
        }
    }
    private void PlayerNextLabel_Click(object sender, EventArgs e)
    {
        int line_index = GetCurrentLineIndex() + 1;
        if (line_index < MainTextBox.Lines.Length)
        {
            bool player_is_opened = false;
            if (m_mp3player != null)
            {
                player_is_opened = m_mp3player.Opened;
                PlayerStopLabel_Click(null, null);
            }

            if (m_found_verses_displayed)
            {
                m_found_verses_current_line_index = line_index;
            }
            else
            {
                m_current_line_index = line_index;
            }
            GotoLine(line_index);

            if (m_mp3player != null)
            {
                if (player_is_opened)
                {
                    PlayerPlayLabel_Click(null, null);
                }
            }
        }
    }
    private void PlayerPlayLabel_Click(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            if ((m_mp3player.Closed) || (m_mp3player.Stopped) || (m_mp3player.Paused))
            {
                if (File.Exists("Images/player_pause.png"))
                {
                    PlayerPlayLabel.Image = new Bitmap("Images/player_pause.png");
                }
                ToolTip.SetToolTip(PlayerPlayLabel, "Pause");
                PlayerPlayLabel.Refresh();

                Verse verse = GetCurrentVerse();
                if (verse != null)
                {
                    try
                    {
                        if (m_mp3player != null)
                        {
                            if (m_mp3player.Closed)
                            {
                                PlayerOpenAudioFile(verse);
                            }

                            if (m_mp3player.Opened)
                            {
                                if (m_mp3player.MuteAll)
                                {
                                    m_mp3player.VolumeAll = 0;
                                }
                                else
                                {
                                    m_mp3player.VolumeAll = m_audio_volume;
                                }

                                m_mp3player.Play();
                                PlayerTimer.Enabled = true;
                                PlayerStopLabel.Enabled = true;
                                PlayerStopLabel.Refresh();
                            }
                        }
                    }
                    catch
                    {
                        PlayerStopLabel_Click(null, null);
                    }

                    // simulate mouse click inside MainTextBox to continue playing next verse and not restart from 1
                    m_is_selection_mode = false;
                    MainTextBox.Focus();
                }
            }
            else if (m_mp3player.Playing)
            {
                if (File.Exists("Images/player_play.png"))
                {
                    PlayerPlayLabel.Image = new Bitmap("Images/player_play.png");
                }
                ToolTip.SetToolTip(PlayerPlayLabel, "Play");
                PlayerPlayLabel.Refresh();

                m_mp3player.Pause();
                PlayerStopLabel.Enabled = true;
                PlayerStopLabel.Refresh();
            }
        }
    }
    private void PlayerStopLabel_Click(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            if (m_mp3player.Opened)
            {
                m_mp3player.Stop();
                m_mp3player.Close();
            }
            PlayerTimer.Enabled = false;
            PlayerStopLabel.Enabled = false;
            PlayerStopLabel.Refresh();
            if (File.Exists("Images/player_play.png"))
            {
                PlayerPlayLabel.Image = new Bitmap("Images/player_play.png");
            }
            PlayerPlayLabel.Refresh();
        }
    }
    private void PlayerRepeatLabel_Click(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            //m_player.Looping = !m_player.Looping;
            //if (m_player.Looping)
            m_playerLooping = !m_playerLooping; // manual looping to allow different reciters to read the same verse
            if (m_playerLooping)
            {
                if (File.Exists("Images/player_repeat_on.png"))
                {
                    PlayerRepeatLabel.Image = new Bitmap("Images/player_repeat_on.png");
                }
            }
            else
            {
                if (File.Exists("Images/player_repeat.png"))
                {
                    PlayerRepeatLabel.Image = new Bitmap("Images/player_repeat.png");
                }
            }
            PlayerRepeatLabel.Refresh();
        }
    }
    private void PlayerRepeatSelectionLabel_Click(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            m_playerLoopingAll = !m_playerLoopingAll;
            if (m_playerLoopingAll)
            {
                if (File.Exists("Images/player_repeat_all_on.png"))
                {
                    PlayerRepeatSelectionLabel.Image = new Bitmap("Images/player_repeat_all_on.png");
                }
            }
            else
            {
                if (File.Exists("Images/player_repeat_all.png"))
                {
                    PlayerRepeatSelectionLabel.Image = new Bitmap("Images/player_repeat_all.png");
                }
            }
            PlayerRepeatSelectionLabel.Refresh();
        }
    }
    private void PlayerMuteLabel_Click(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            m_mp3player.MuteAll = !m_mp3player.MuteAll;
            if (m_mp3player.MuteAll)
            {
                m_mp3player.VolumeAll = 0;
                if (File.Exists("Images/player_muted.png"))
                {
                    PlayerMuteLabel.Image = new Bitmap("Images/player_muted.png");
                }
            }
            else
            {
                m_mp3player.VolumeAll = m_audio_volume;
                if (File.Exists("Images/player_vol_hi.png"))
                {
                    PlayerMuteLabel.Image = new Bitmap("Images/player_vol_hi.png");
                }
            }
            PlayerMuteLabel.Refresh();
        }
    }
    private void PlayerVolumeTrackBar_Scroll(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            m_audio_volume = PlayerVolumeTrackBar.Value * (1000 / PlayerVolumeTrackBar.Maximum);
            m_mp3player.VolumeAll = m_audio_volume;
            ToolTip.SetToolTip(PlayerVolumeTrackBar, "Volume " + (m_audio_volume / (1000 / PlayerVolumeTrackBar.Maximum)).ToString() + "%");
        }
    }
    private void PlayerSilenceTrackBar_Scroll(object sender, EventArgs e)
    {
        if (m_mp3player != null)
        {
            m_silence_between_verses = (float)PlayerSilenceTrackBar.Value / (PlayerSilenceTrackBar.Maximum / 2);
            ToolTip.SetToolTip(PlayerSilenceTrackBar, "Silence " + m_silence_between_verses.ToString("0.0") + " verses");
        }
    }

    private List<string> m_downloaded_reciter_folders = null;
    private void DownloadFile(string url, string path)
    {
        string download_folder = Path.GetDirectoryName(path);
        if (!Directory.Exists(download_folder))
        {
            Directory.CreateDirectory(download_folder);
        }

        Downloader.Download(url, Application.StartupPath + "/" + path, 10000);
        //using (WebClient web_client = new WebClient())
        //{
        //    web_client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(DownloadDataCompleted);
        //    web_client.DownloadDataAsync(new Uri(url));
        //}
    }
    //private void DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
    //{
    //    // WARNING: runs on different thread to UI thread
    //    byte[] raw = e.Result;
    //}
    private void AskUserToDownloadAudioFilesManually()
    {
        if (MessageBox.Show("Cannot auto-download audio files.\r\n\r\n"
                          + "Would you like to manually download audio files\r\n"
                          + "and unzip them to: "
                          + "Audio\\" + m_recitation_folder + "\\" + "\r\n"
                          + "?",
                          Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            Control control = new Control();
            foreach (string key in m_client.Book.RecitationInfos.Keys)
            {
                if (m_client.Book.RecitationInfos[key].Folder == m_recitation_folder)
                {
                    control.Tag = RecitationInfo.DEFAULT_URL_PREFIX + m_client.Book.RecitationInfos[key].Url;
                    LinkLabel_Click(control, null);
                    break;
                }
            }
        }
    }
    private bool DownloadVerseAudioFile(Verse verse)
    {
        // mirror remote_folder locally
        string audio_folder = "Audio" + "/" + m_recitation_folder;
        if (!Directory.Exists(audio_folder))
        {
            Directory.CreateDirectory(audio_folder);
        }

        // generate audio_filename from verse address
        string audio_filename = "";
        string full_audio_folder = "";
        if (verse == null)
        {
            audio_filename = "001000" + "." + RecitationInfo.FileType; // audhubillah
            full_audio_folder = audio_folder + "/" + "001";
        }
        else
        {
            if (verse.Chapter != null)
            {
                audio_filename = verse.Chapter.Number.ToString("000") + verse.NumberInChapter.ToString("000") + "." + RecitationInfo.FileType;
                full_audio_folder = audio_folder + "/" + verse.Chapter.Number.ToString("000");
            }
        }

        // fill up local_audio_filename to return to caller
        m_downloaded_audio_filename = full_audio_folder + "/" + audio_filename;
        string outer_downloaded_audio_filename = audio_folder + "/" + audio_filename;
        if (File.Exists(m_downloaded_audio_filename))
        {
            return true; // no need to download
        }
        else if (File.Exists(outer_downloaded_audio_filename))
        {
            if (!Directory.Exists(full_audio_folder))
            {
                Directory.CreateDirectory(full_audio_folder);
            }

            if (Directory.Exists(full_audio_folder))
            {
                File.Move(outer_downloaded_audio_filename, m_downloaded_audio_filename);
            }

            return true; // no need to download
        }
        else
        {
            // try to download audio file
            this.Cursor = Cursors.WaitCursor;
            try
            {
                string recitation_url = "";
                foreach (string key in m_client.Book.RecitationInfos.Keys)
                {
                    if (m_client.Book.RecitationInfos[key].Folder == m_recitation_folder)
                    {
                        recitation_url = RecitationInfo.UrlPrefix + m_client.Book.RecitationInfos[key].Url + "/" + audio_filename;
                        break;
                    }
                }

                DownloadFile(recitation_url, m_downloaded_audio_filename);
                return true;
            }
            catch
            {
                PlayerStopLabel_Click(null, null);
                return false;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
    }
    private string GetVerseAudioFilename(int verse_index)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                if ((verse_index >= 0) && (verse_index < m_client.Book.Verses.Count))
                {
                    Verse verse = m_client.Book.Verses[verse_index];
                    if (verse != null)
                    {
                        if (verse.Chapter != null)
                        {
                            return (verse.Chapter.Number.ToString("000") + verse.NumberInChapter.ToString("000") + "." + RecitationInfo.FileType);
                        }
                    }
                }
            }
        }
        return "000000.mp3";
    }
    private string GetVerseAudioFullFilename(int verse_index)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                if ((verse_index >= 0) && (verse_index < m_client.Book.Verses.Count))
                {
                    Verse verse = m_client.Book.Verses[verse_index];
                    if (verse != null)
                    {
                        if (verse.Chapter != null)
                        {
                            return (verse.Chapter.Number.ToString("000") + "/" + verse.Chapter.Number.ToString("000") + verse.NumberInChapter.ToString("000") + "." + RecitationInfo.FileType);
                        }
                    }
                }
            }
        }
        return "000/000000.mp3";
    }
    private void WaitForPlayToFinish()
    {
        while ((m_mp3player.Length - m_mp3player.Position) > (ulong)PlayerTimer.Interval)
        {
            Thread.Sleep(100);
        }
    }

    private void PopulateChapterComboBox()
    {
        try
        {
            ChapterComboBox.SelectedIndexChanged -= new EventHandler(ChapterComboBox_SelectedIndexChanged);
            if (m_client != null)
            {
                if (m_client.Book != null)
                {
                    ChapterComboBox.BeginUpdate();
                    ChapterComboBox.Items.Clear();
                    foreach (Chapter chapter in m_client.Book.Chapters)
                    {
                        ChapterComboBox.Items.Add(chapter.Number + " - " + chapter.Name);
                    }
                }
            }
        }
        finally
        {
            ChapterComboBox.EndUpdate();
            ChapterComboBox.SelectedIndexChanged += new EventHandler(ChapterComboBox_SelectedIndexChanged);
        }
    }
    private void PopulateChaptersListBox()
    {
        try
        {
            ChaptersListBox.SelectedIndexChanged -= new EventHandler(ChaptersListBox_SelectedIndexChanged);
            if (m_client != null)
            {
                if (m_client.Book != null)
                {
                    ChaptersListBox.BeginUpdate();
                    ChaptersListBox.Items.Clear();
                    foreach (Chapter chapter in m_client.Book.Chapters)
                    {
                        ChaptersListBox.Items.Add(chapter.Number + " - " + chapter.Name);
                    }
                }
            }
        }
        finally
        {
            ChaptersListBox.EndUpdate();
            ChaptersListBox.SelectedIndexChanged += new EventHandler(ChaptersListBox_SelectedIndexChanged);
        }
    }
    private void PopulateRecitationsCheckedListBox()
    {
        try
        {
            // to disable item in a list, just ignore user check using this trick
            RecitationsCheckedListBox.ItemCheck += new ItemCheckEventHandler(RecitationsCheckedListBox_ItemCheck);

            RecitationsCheckedListBox.SelectedIndexChanged -= new EventHandler(RecitationsCheckedListBox_SelectedIndexChanged);
            RecitationsCheckedListBox.BeginUpdate();
            RecitationsCheckedListBox.Items.Clear();
            foreach (string key in m_client.Book.RecitationInfos.Keys)
            {
                string reciter = m_client.Book.RecitationInfos[key].Reciter;
                RecitationsCheckedListBox.Items.Add(reciter);
            }
        }
        finally
        {
            RecitationsCheckedListBox.EndUpdate();
            RecitationsCheckedListBox.SelectedIndexChanged += new EventHandler(RecitationsCheckedListBox_SelectedIndexChanged);
        }
    }
    private void RecitationsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (e.CurrentValue == CheckState.Indeterminate)
        {
            e.NewValue = e.CurrentValue;
        }
    }
    private void PopulateRecitationsComboBox()
    {
        try
        {
            RecitationsComboBox.BeginUpdate();
            RecitationsComboBox.SelectedIndexChanged -= new EventHandler(RecitationsComboBox_SelectedIndexChanged);
            RecitationsComboBox.Items.Clear();
            foreach (string key in m_client.Book.RecitationInfos.Keys)
            {
                string reciter = m_client.Book.RecitationInfos[key].Reciter;
                RecitationsComboBox.Items.Add(reciter);
            }
            if (RecitationsComboBox.Items.Count > 3)
            {
                RecitationsComboBox.SelectedIndex = 3;
            }
        }
        finally
        {
            RecitationsComboBox.EndUpdate();
            RecitationsComboBox.SelectedIndexChanged += new EventHandler(RecitationsComboBox_SelectedIndexChanged);
        }
    }
    private void UpdateRecitationsCheckedListBox()
    {
        this.Cursor = Cursors.WaitCursor;
        try
        {
            /////////////////////////////////////////////////////////////////////////////
            // foreach reciter -> foreach verse, if audio file exist and valid then check
            /////////////////////////////////////////////////////////////////////////////

            if (m_downloaded_reciter_folders == null)
            {
                m_downloaded_reciter_folders = new List<string>();
            }
            m_downloaded_reciter_folders.Clear();

            string recitations_folder = "Audio";
            foreach (string reciter_folder in m_client.Book.RecitationInfos.Keys)
            {
                bool fully_downloaded = true;
                for (int i = 0; i < Verse.MAX_NUMBER; i++)
                {
                    string download_folder = recitations_folder + "/" + reciter_folder;
                    string filename = GetVerseAudioFilename(i); // e.g. i=8 ==> 002001.mp3
                    string full_filename = GetVerseAudioFullFilename(i); // e.g. i=8 ==> 002/002001.mp3
                    string full_path = download_folder + "/" + full_filename;
                    if (File.Exists(full_path)) // file exist
                    {
                        long filesize = (new FileInfo(full_path)).Length;
                        if (filesize < 1024) // invalid file
                        {
                            fully_downloaded = false;
                            break;
                        }
                    }
                    else // file not found
                    {
                        fully_downloaded = false;
                        break;
                    }
                }

                int index = 0;
                string reciter = m_client.Book.RecitationInfos[reciter_folder].Reciter;
                for (int i = 0; i < RecitationsCheckedListBox.Items.Count; i++)
                {
                    if (RecitationsCheckedListBox.Items[i].ToString() == reciter)
                    {
                        index = i;
                    }
                }

                if (fully_downloaded)
                {
                    RecitationsCheckedListBox.SetItemCheckState(index, CheckState.Indeterminate);
                    m_downloaded_reciter_folders.Add(reciter_folder);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void RecitationsCheckedListBox_SelectedIndexChanged(object sender, EventArgs e)
    {
    }
    private void RecitationsCheckedListBox_MouseUp(object sender, MouseEventArgs e)
    {
        if (RecitationsCheckedListBox.SelectedItem != null)
        {
            string reciter = RecitationsCheckedListBox.SelectedItem.ToString();

            string reciter_folder = "";
            foreach (string key in m_client.Book.RecitationInfos.Keys)
            {
                if (reciter == m_client.Book.RecitationInfos[key].Reciter)
                {
                    reciter_folder = key;
                    break;
                }
            }

            if (m_downloaded_reciter_folders.Contains(reciter_folder))
            {
                RecitationsCheckedListBox.SetItemCheckState(RecitationsCheckedListBox.SelectedIndex, CheckState.Indeterminate);
            }
        }
    }
    private void RecitationsComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (RecitationsComboBox.SelectedItem != null)
        {
            string reciter = RecitationsComboBox.SelectedItem.ToString();
            foreach (string key in m_client.Book.RecitationInfos.Keys)
            {
                if (m_client.Book.RecitationInfos[key].Reciter == reciter)
                {
                    m_recitation_folder = m_client.Book.RecitationInfos[key].Folder;
                    break;
                }
            }
            RecitationGroupBox.Text = reciter;
        }
    }
    private void RecitationsApplySettingsLabel_Click(object sender, EventArgs e)
    {
        if (!RecitationsDownloadGroupBox.Visible)
        {
            UpdateRecitationsCheckedListBox();

            RecitationsDownloadGroupBox.Visible = true;
            RecitationsCancelSettingsLabel.Visible = true;
            RecitationsDownloadGroupBox.BringToFront();

            if (File.Exists("Images/apply.png"))
            {
                RecitationsApplySettingsLabel.Image = new Bitmap("Images/apply.png");
            }
            ToolTip.SetToolTip(RecitationsApplySettingsLabel, "Download complete audio files for selected recitors");
        }
        else
        {
            RecitationsDownloadGroupBox.Visible = false;
            RecitationsCancelSettingsLabel.Visible = false;
            RecitationsDownloadGroupBox.SendToBack();

            this.Cursor = Cursors.WaitCursor;
            try
            {
                if (File.Exists("Images/settings.png"))
                {
                    RecitationsApplySettingsLabel.Image = new Bitmap("Images/settings.png");
                }
                ToolTip.SetToolTip(RecitationsApplySettingsLabel, "Add/Remove recitations");

                List<string> keys_to_download = new List<string>();
                foreach (int cheched_index in RecitationsCheckedListBox.CheckedIndices)
                {
                    if (RecitationsCheckedListBox.GetItemCheckState(cheched_index) != CheckState.Indeterminate)
                    {
                        foreach (string key in m_client.Book.RecitationInfos.Keys)
                        {
                            string reciter = RecitationsCheckedListBox.Items[cheched_index].ToString();
                            if (m_client.Book.RecitationInfos[key].Reciter == reciter)
                            {
                                keys_to_download.Add(key);
                                break;
                            }
                        }
                    }
                }

                string recitations_folder = "Audio";
                foreach (string reciter_folder in m_client.Book.RecitationInfos.Keys)
                {
                    if (keys_to_download.Contains(reciter_folder))
                    {
                        ProgressBar.Minimum = Verse.MIN_NUMBER;
                        ProgressBar.Maximum = Verse.MAX_NUMBER;
                        ProgressBar.Value = 1;
                        ProgressBar.Refresh();

                        for (int i = 0; i < Verse.MAX_NUMBER; i++)
                        {
                            string download_folder = recitations_folder + "/" + reciter_folder;
                            string filename = GetVerseAudioFilename(i); // e.g. i=8 ==> 002001.mp3
                            string full_filename = GetVerseAudioFullFilename(i); // e.g. i=8 ==> 002/002001.mp3
                            string full_path = download_folder + "/" + full_filename;
                            if (File.Exists(full_path)) // file exist
                            {
                                long filesize = (new FileInfo(full_path)).Length;
                                if (filesize < 1024) // if < 1kb invalid file then re-download
                                {
                                    DownloadFile(RecitationInfo.UrlPrefix + m_client.Book.RecitationInfos[reciter_folder].Url + "/" + filename, full_path);
                                }
                            }
                            else // file not found so download it
                            {
                                DownloadFile(RecitationInfo.UrlPrefix + m_client.Book.RecitationInfos[reciter_folder].Url + "/" + filename, full_path);
                            }

                            ProgressBar.Value = i + 1;
                            ProgressBar.Refresh();

                            Application.DoEvents();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName);
            }
            finally
            {
                if (m_client != null)
                {
                    if (m_client.Selection != null)
                    {
                        List<Verse> verses = m_client.Selection.Verses;
                        if (verses.Count > 0)
                        {
                            ProgressBar.Minimum = Verse.MIN_NUMBER;
                            ProgressBar.Maximum = Verse.MAX_NUMBER;
                            ProgressBar.Value = verses[0].Number;
                            ProgressBar.Refresh();
                        }
                        this.Cursor = Cursors.Default;
                    }
                }
            }
        }
        RecitationsApplySettingsLabel.Refresh();
    }
    private void RecitationsCancelSettingsLabel_Click(object sender, EventArgs e)
    {
        RecitationsDownloadGroupBox.Visible = false;
        RecitationsDownloadGroupBox.Refresh();
        RecitationsCancelSettingsLabel.Visible = RecitationsDownloadGroupBox.Visible;
        RecitationsCancelSettingsLabel.Refresh();
        if (File.Exists("Images/settings.png"))
        {
            RecitationsApplySettingsLabel.Image = new Bitmap("Images/settings.png");
        }
        ToolTip.SetToolTip(RecitationsApplySettingsLabel, "Setup recitations");
        PopulateRecitationsCheckedListBox();
    }

    private void PopulateTranslatorsCheckedListBox()
    {
        try
        {
            // to disable item in a list, just ignore user check using this trick
            TranslatorsCheckedListBox.ItemCheck += new ItemCheckEventHandler(TranslatorsCheckedListBox_ItemCheck);

            TranslatorsCheckedListBox.SelectedIndexChanged -= new EventHandler(TranslatorsCheckedListBox_SelectedIndexChanged);
            TranslatorsCheckedListBox.BeginUpdate();
            TranslatorsCheckedListBox.Items.Clear();

            if (m_client.Book != null)
            {
                if (m_client.Book.Verses != null)
                {
                    if (m_client.Book.Verses.Count > 0)
                    {
                        List<string> checked_keys = new List<string>();
                        foreach (string key in m_client.Book.Verses[0].Translations.Keys)
                        {
                            checked_keys.Add(key);
                        }

                        // populate TranslatorsCheckedListBox
                        if (m_client.Book.TranslationInfos != null)
                        {
                            foreach (string key in m_client.Book.TranslationInfos.Keys)
                            {
                                string name = m_client.Book.TranslationInfos[key].Name;
                                bool is_checked = checked_keys.Contains(key);
                                TranslatorsCheckedListBox.Items.Add(name, is_checked);
                            }

                            // disable list item if default so user cannot uncheck it
                            for (int i = 0; i < TranslatorsCheckedListBox.Items.Count; i++)
                            {
                                string item_text = TranslatorsCheckedListBox.Items[i].ToString();
                                foreach (string key in m_client.Book.TranslationInfos.Keys)
                                {
                                    string name = m_client.Book.TranslationInfos[key].Name;
                                    if (name == item_text)
                                    {
                                        if (
                                            (key == Client.DEFAULT_EMLAAEI) ||
                                            (key == Client.DEFAULT_TRANSLATION) ||
                                            (key == Client.DEFAULT_TRANSLITERATION)
                                           )
                                        {
                                            TranslatorsCheckedListBox.SetItemCheckState(i, CheckState.Indeterminate);
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            TranslatorsCheckedListBox.Sorted = true;
            TranslatorsCheckedListBox.EndUpdate();
            TranslatorsCheckedListBox.SelectedIndexChanged += new EventHandler(TranslatorsCheckedListBox_SelectedIndexChanged);
        }
    }
    private void TranslatorsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        if (e.CurrentValue == CheckState.Indeterminate)
        {
            e.NewValue = e.CurrentValue;
        }
    }
    private void PopulateTranslatorComboBox()
    {
        try
        {
            if (m_client.Book != null)
            {
                if (m_client.Book.Verses.Count > 0)
                {
                    if (m_client.Book.Verses[0].Translations != null)
                    {
                        if (m_client.Book.Verses[0].Translations.Count == 0)
                        {
                            DownloadTranslations();
                        }

                        string backup_translation_name = "";
                        if (TranslatorComboBox.SelectedItem != null)
                        {
                            backup_translation_name = TranslatorComboBox.SelectedItem.ToString();
                        }

                        TranslatorComboBox.BeginUpdate();
                        TranslatorComboBox.Items.Clear();
                        foreach (string key in m_client.Book.Verses[0].Translations.Keys)
                        {
                            string name = m_client.Book.TranslationInfos[key].Name;
                            TranslatorComboBox.Items.Add(name);
                        }

                        if (backup_translation_name.Length > 0)
                        {
                            bool found = false;
                            for (int i = 0; i < TranslatorComboBox.Items.Count; i++)
                            {
                                if (TranslatorComboBox.Items[i].ToString() == backup_translation_name)
                                {
                                    found = true;
                                    break;
                                }
                            }
                            if (found)
                            {
                                this.TranslatorComboBox.SelectedItem = backup_translation_name;
                            }
                            else
                            {
                                this.TranslatorComboBox.SelectedItem = m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLATION].Name;
                            }
                        }
                        else // if all translations were cleared, we still have the 3 mandatory ones at minimum
                        {
                            if (this.TranslatorComboBox.Items.Count >= 3)
                            {
                                this.TranslatorComboBox.SelectedItem = m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLATION].Name;
                            }
                            else // if user deleted one or more of the 3 mandatory translations manually
                            {
                                if (this.TranslatorComboBox.Items.Count > 0)
                                {
                                    this.TranslatorComboBox.SelectedItem = 0;
                                }
                                else // if no transaltion at all was left
                                {
                                    TranslatorComboBox.SelectedIndex = -1;
                                }
                            }
                        }
                    }
                }
            }
        }
        catch
        {
            TranslatorComboBox.SelectedIndex = -1;
        }
        finally
        {
            TranslatorComboBox.Sorted = true;
            TranslatorComboBox.EndUpdate();
        }
    }
    private void TranslatorsCheckedListBox_SelectedIndexChanged(object sender, EventArgs e)
    {
    }
    //private void TranslatorsCheckedListBox_MouseUp(object sender, MouseEventArgs e)
    //{
    //    if (TranslatorsCheckedListBox.SelectedItem != null)
    //    {
    //        string name = TranslatorsCheckedListBox.SelectedItem.ToString();
    //        if (
    //            (name == m_client.Book.TranslationInfos[Client.DEFAULT_EMLAAEI].Name) ||
    //            (name == m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLATION].Name) ||
    //            (name == m_client.Book.TranslationInfos[Client.DEFAULT_TRANSLITERATION].Name)
    //           )
    //        {
    //            TranslatorsCheckedListBox.SetItemCheckState(TranslatorsCheckedListBox.SelectedIndex, CheckState.Indeterminate);
    //        }
    //    }
    //}
    private void TranslationsApplySettingsLabel_Click(object sender, EventArgs e)
    {
        TranslatorsCheckedListBox.Visible = !TranslatorsCheckedListBox.Visible;
        TranslationsCancelSettingsLabel.Visible = TranslatorsCheckedListBox.Visible;
        TranslatorComboBox.Visible = TranslatorsCheckedListBox.Visible;

        if (TranslatorsCheckedListBox.Visible)
        {
            if (File.Exists("Images/apply.png"))
            {
                TranslationsApplySettingsLabel.Image = new Bitmap("Images/apply.png");
            }
            ToolTip.SetToolTip(TranslationsApplySettingsLabel, "Download translations");
        }
        else
        {
            if (File.Exists("Images/settings.png"))
            {
                TranslationsApplySettingsLabel.Image = new Bitmap("Images/settings.png");
            }
            ToolTip.SetToolTip(TranslationsApplySettingsLabel, "Add/Remove translations");

            int index_of_first_new_translation = DownloadTranslations();
            if ((index_of_first_new_translation >= 0) && (index_of_first_new_translation < TranslatorComboBox.Items.Count))
            {
                TranslatorComboBox.SelectedIndex = index_of_first_new_translation;
            }
        }

        this.AcceptButton = null;
    }
    private void TranslationsCancelSettingsLabel_Click(object sender, EventArgs e)
    {
        TranslatorsCheckedListBox.Visible = false;
        TranslationsCancelSettingsLabel.Visible = TranslatorsCheckedListBox.Visible;
        TranslatorComboBox.Visible = TranslatorsCheckedListBox.Visible;

        if (File.Exists("Images/settings.png"))
        {
            TranslationsApplySettingsLabel.Image = new Bitmap("Images/settings.png");
        }
        ToolTip.SetToolTip(TranslationsApplySettingsLabel, "Add/Remove translations");
        PopulateTranslatorsCheckedListBox();

        this.AcceptButton = null;
    }
    private void ClientSplitContainer_SplitterMoved(object sender, SplitterEventArgs e)
    {
        if ((ClientSplitContainer.Height - ClientSplitContainer.SplitterDistance) > 40)
        {
            m_translation_box_top = this.ClientSplitContainer.SplitterDistance;
        }
    }
    private void TranslatorComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_is_selection_mode)
                {
                    if (m_found_verses_displayed)
                    {
                        DisplayTranslation(m_client.FoundVerses);
                    }
                    else
                    {
                        List<Verse> verses = m_client.Selection.Verses;
                        DisplayTranslation(verses);
                    }
                }
                else // highlighted text or current line
                {
                    int line_index = -1;
                    if (m_found_verses_displayed)
                    {
                        line_index = m_found_verses_current_line_index;
                    }
                    else
                    {
                        line_index = m_current_line_index;
                    }

                    if (m_found_verses_displayed)
                    {
                        if (m_client.FoundVerses != null)
                        {
                            if ((line_index >= 0) && (line_index < m_client.FoundVerses.Count))
                            {
                                DisplayTranslation(m_client.FoundVerses[line_index]);
                            }
                        }
                    }
                    else
                    {
                        List<Verse> verses = m_client.Selection.Verses;
                        if ((line_index >= 0) && (line_index < verses.Count))
                        {
                            DisplayTranslation(verses[line_index]);
                        }
                    }
                }
            }
        }
    }
    /// <summary>
    /// Download all new requested translations
    /// </summary>
    /// <returns>index of first new transaltion</returns>
    private int DownloadTranslations()
    {
        int index_of_first_new_transaltion = -1;

        this.Cursor = Cursors.WaitCursor;
        try
        {
            List<string> checked_keys = new List<string>();
            if (m_client.Book.TranslationInfos != null)
            {
                foreach (string key in m_client.Book.TranslationInfos.Keys)
                {
                    if (
                        (key == Client.DEFAULT_EMLAAEI) ||
                        (key == Client.DEFAULT_TRANSLATION) ||
                        (key == Client.DEFAULT_TRANSLITERATION)
                       )
                    {
                        checked_keys.Add(key);
                    }
                    else
                    {
                        foreach (int index in TranslatorsCheckedListBox.CheckedIndices)
                        {
                            if (m_client.Book.TranslationInfos[key].Name == TranslatorsCheckedListBox.Items[index].ToString())
                            {
                                checked_keys.Add(key);
                                break;
                            }
                        }
                    }
                }

                string translations_folder = "Translations";
                string offline_folder = translations_folder + "/" + "Offline";
                ProgressBar.Minimum = 0;
                ProgressBar.Maximum = checked_keys.Count;
                ProgressBar.Value = 0;
                ProgressBar.Refresh();

                string[] keys = new string[m_client.Book.TranslationInfos.Keys.Count];
                m_client.Book.TranslationInfos.Keys.CopyTo(keys, 0);
                foreach (string key in keys)
                {
                    if (checked_keys.Contains(key))
                    {
                        ProgressBar.Value++;
                        ProgressBar.Refresh();

                        string translations_path = translations_folder + "/" + key + ".txt";
                        string offline_path = offline_folder + "/" + key + ".txt";

                        // delete file in translations_path if invalid
                        if (File.Exists(translations_path))
                        {
                            long filesize = (new FileInfo(translations_path)).Length;
                            if (filesize < 1024) // < 1kb invalid file
                            {
                                File.Delete(translations_path);
                            }
                        }

                        // delete file in offline_path if invalid
                        if (File.Exists(offline_path))
                        {
                            long filesize = (new FileInfo(offline_path)).Length;
                            if (filesize < 1024) // < 1kb invalid file
                            {
                                File.Delete(offline_path);
                            }
                        }

                        if (!File.Exists(translations_path))
                        {
                            // download file to offline_path
                            if (!File.Exists(offline_path))
                            {
                                DownloadFile(TranslationInfo.UrlPrefix + m_client.Book.TranslationInfos[key].Url, offline_path);
                            }

                            // copy to translations_path
                            if (File.Exists(offline_path))
                            {
                                long filesize = (new FileInfo(offline_path)).Length;
                                if (filesize < 1024) // < 1kb invalid file
                                {
                                    File.Delete(offline_path);
                                    m_client.UnloadTranslation(key);
                                }
                                else // copy valid file
                                {
                                    File.Copy(offline_path, translations_path);
                                    m_client.LoadTranslation(key);
                                }
                            }

                            // get index of first new translation
                            if (index_of_first_new_transaltion == -1)
                            {
                                int index_of_new_transaltion = -1;
                                foreach (int index in TranslatorsCheckedListBox.CheckedIndices)
                                {
                                    index_of_new_transaltion++;
                                    if (m_client.Book.TranslationInfos[key].Name == TranslatorsCheckedListBox.Items[index].ToString())
                                    {
                                        index_of_first_new_transaltion = index_of_new_transaltion;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else // unload translation
                    {
                        if (File.Exists(translations_folder + "/" + key + ".txt"))
                        {
                            m_client.UnloadTranslation(key);
                            File.Delete(translations_folder + "/" + key + ".txt");
                        }
                    }

                    Application.DoEvents();
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            PopulateTranslatorsCheckedListBox();
            PopulateTranslatorComboBox();

            if (m_client != null)
            {
                if (m_client.Selection != null)
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses.Count > 0)
                    {
                        ProgressBar.Minimum = Verse.MIN_NUMBER;
                        ProgressBar.Maximum = Verse.MAX_NUMBER;
                        ProgressBar.Value = verses[0].Number;
                        ProgressBar.Refresh();
                    }
                }
            }

            this.Cursor = Cursors.Default;
        }

        return index_of_first_new_transaltion;
    }
    private void DisplayTranslation(List<Verse> verses)
    {
        if (verses != null)
        {
            if (TranslatorComboBox.SelectedItem != null)
            {
                string name = TranslatorComboBox.SelectedItem.ToString();
                string translation = m_client.GetTranslationKey(name);
                DisplayTranslation(verses, translation);
            }
        }
    }
    private void DisplayTranslation(Verse verse)
    {
        if (verse != null)
        {
            if (TranslatorComboBox.SelectedItem != null)
            {
                string name = TranslatorComboBox.SelectedItem.ToString();
                string translation = m_client.GetTranslationKey(name);
                DisplayTranslation(verse, translation);
            }
        }
    }
    private void DisplayTranslation(Verse verse, string translation)
    {
        if (verse != null)
        {
            if (verse.Translations.ContainsKey(translation))
            {
                TranslationTextBox.WordWrap = true;
                TranslationTextBox.Text = (verse.PaddedAddress + " " + verse.Translations[translation]);
                TranslationTextBox.Refresh();
            }
        }
    }
    private void DisplayTranslation(List<Verse> verses, string translation)
    {
        if (verses != null)
        {
            if (verses.Count > 0)
            {
                if (verses[0].Translations.ContainsKey(translation))
                {
                    StringBuilder str = new StringBuilder();
                    foreach (Verse verse in verses)
                    {
                        str.AppendLine(verse.PaddedAddress + " " + verse.Translations[translation]);
                    }
                    str.Remove(str.Length - 2, 2);

                    TranslationTextBox.WordWrap = (verses.Count == 1);
                    TranslationTextBox.Text = str.ToString();
                    TranslationTextBox.Refresh();
                }
            }
        }
    }
    private void SaveTranslationLabel_Click(object sender, EventArgs e)
    {
        // TODO Save edited translation
    }

    private void ChapterComboBox_KeyDown(object sender, KeyEventArgs e)
    {
        bool SeparatorKeys = (
            ((e.KeyCode == Keys.Subtract) && (e.Modifiers != Keys.Shift))           // HYPHEN
            || ((e.KeyCode == Keys.OemMinus) && (e.Modifiers != Keys.Shift))        // HYPHEN
            || ((e.KeyCode == Keys.Oemcomma) && (e.Modifiers != Keys.Shift))        // COMMA
            || ((e.KeyCode == Keys.OemSemicolon) && (e.Modifiers == Keys.Shift))    // COLON
            );

        bool NumericKeys = (
            ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) || (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9))
            && e.Modifiers != Keys.Shift);

        bool EditKeys = (
            (e.KeyCode == Keys.A && e.Modifiers == Keys.Control) ||
            (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control) ||
            (e.KeyCode == Keys.X && e.Modifiers == Keys.Control) ||
            (e.KeyCode == Keys.C && e.Modifiers == Keys.Control) ||
            (e.KeyCode == Keys.V && e.Modifiers == Keys.Control) ||
            e.KeyCode == Keys.Delete ||
            e.KeyCode == Keys.Back);

        bool NavigationKeys = (
            e.KeyCode == Keys.Up ||
            e.KeyCode == Keys.Right ||
            e.KeyCode == Keys.Down ||
            e.KeyCode == Keys.Left ||
            e.KeyCode == Keys.Home ||
            e.KeyCode == Keys.End);

        bool ExecuteKeys = (e.KeyCode == Keys.Enter);

        if (ExecuteKeys)
        {
            if (m_client != null)
            {
                try
                {
                    string text = ChapterComboBox.Text;
                    if (text.Length > 0)
                    {
                        // 1, 3-4, 5:55, 3-4:19, 6:19-23, 24:35-27:62
                        SelectionScope scope = SelectionScope.Verse;
                        List<int> indexes = new List<int>();

                        foreach (string part in text.Split(','))
                        {
                            string[] range_parts = part.Split('-');
                            if (range_parts.Length == 1) // 1 | 5:55
                            {
                                string[] sub_range_parts = part.Split(':');
                                if (sub_range_parts.Length == 1) // 1
                                {
                                    int chapter_number;
                                    if (int.TryParse(sub_range_parts[0], out chapter_number))
                                    {
                                        Chapter chapter = null;
                                        foreach (Chapter book_chapter in m_client.Book.Chapters)
                                        {
                                            if (book_chapter.Number == chapter_number)
                                            {
                                                chapter = book_chapter;
                                            }
                                        }
                                        foreach (Verse verse in chapter.Verses)
                                        {
                                            indexes.Add(verse.Number - 1);
                                        }
                                    }
                                }
                                else if (sub_range_parts.Length == 2) // 5:55
                                {
                                    int chapter_number;
                                    if (int.TryParse(sub_range_parts[0], out chapter_number)) // 5:55
                                    {
                                        int verse_number_in_chapter;
                                        if (int.TryParse(sub_range_parts[1], out verse_number_in_chapter))
                                        {
                                            Chapter chapter = null;
                                            foreach (Chapter book_chapter in m_client.Book.Chapters)
                                            {
                                                if (book_chapter.Number == chapter_number)
                                                {
                                                    chapter = book_chapter;
                                                }
                                            }
                                            int from_verse_index = chapter.Verses[verse_number_in_chapter - 1].Number - 1;
                                            indexes.Add(from_verse_index);
                                        }
                                    }
                                }
                            }
                            else if (range_parts.Length == 2) // 3-4, 3-4:19, 6:19-23, 24:35-27:62
                            {
                                int from_chapter_number;
                                int to_chapter_number;
                                if (int.TryParse(range_parts[0], out from_chapter_number)) // 3-4
                                {
                                    if (int.TryParse(range_parts[1], out to_chapter_number))
                                    {
                                        if (from_chapter_number <= to_chapter_number)
                                        {
                                            for (int number = from_chapter_number; number <= to_chapter_number; number++)
                                            {
                                                Chapter chapter = null;
                                                foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                {
                                                    if (book_chapter.Number == number)
                                                    {
                                                        chapter = book_chapter;
                                                    }
                                                }
                                                foreach (Verse verse in chapter.Verses)
                                                {
                                                    indexes.Add(verse.Number - 1);
                                                }
                                            }
                                        }
                                    }
                                    else // 3-4:19
                                    {
                                        // range_parts[0] == 3
                                        // range_parts[1] == 4:19
                                        string[] to_range_parts = range_parts[1].Split(':'); // 4:19
                                        if (to_range_parts.Length == 2)
                                        {
                                            int from_verse_number_in_chapter = 1; // not specified so start from beginning of chapter

                                            if (int.TryParse(to_range_parts[0], out to_chapter_number))  // 4
                                            {
                                                int to_verse_number_in_chapter;
                                                if (int.TryParse(to_range_parts[1], out to_verse_number_in_chapter)) // 19
                                                {
                                                    Chapter from_chapter = null;
                                                    foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                    {
                                                        if (book_chapter.Number == from_chapter_number)
                                                        {
                                                            from_chapter = book_chapter;
                                                        }
                                                    }
                                                    int from_verse_index = from_chapter.Verses[from_verse_number_in_chapter - 1].Number - 1;

                                                    Chapter to_chapter = null;
                                                    foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                    {
                                                        if (book_chapter.Number == to_chapter_number)
                                                        {
                                                            to_chapter = book_chapter;
                                                        }
                                                    }
                                                    int to_verse_index = to_chapter.Verses[to_verse_number_in_chapter - 1].Number - 1;
                                                    for (int i = from_verse_index; i <= to_verse_index; i++)
                                                    {
                                                        indexes.Add(i);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else // "range_parts[0]" contains a colon ':'  // "6:19"-23, "24:35"-27:62
                                {
                                    //int from_chapter_number;
                                    //int to_chapter_number;
                                    string[] from_parts = range_parts[0].Split(':');
                                    if (from_parts.Length == 2)
                                    {
                                        int from_verse_number_in_chapter;
                                        if (int.TryParse(from_parts[0], out from_chapter_number))
                                        {
                                            if (int.TryParse(from_parts[1], out from_verse_number_in_chapter))
                                            {
                                                string[] to_parts = range_parts[1].Split(':'); // "range_parts[1]" may or may not contain a colon ':'  // 6:19-"23", 24:35-"27:62"
                                                if (to_parts.Length == 1) // 6:19-"23"
                                                {
                                                    int to_verse_number_in_chapter;
                                                    if (int.TryParse(to_parts[0], out to_verse_number_in_chapter))
                                                    {
                                                        if (from_verse_number_in_chapter <= to_verse_number_in_chapter)  // XX:19-23
                                                        {
                                                            Chapter from_chapter = null;
                                                            foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                            {
                                                                if (book_chapter.Number == from_chapter_number)
                                                                {
                                                                    from_chapter = book_chapter;
                                                                }
                                                            }
                                                            int from_verse_index = from_chapter.Verses[from_verse_number_in_chapter - 1].Number - 1;
                                                            int to_verse_index = from_chapter.Verses[to_verse_number_in_chapter - 1].Number - 1;
                                                            for (int i = from_verse_index; i <= to_verse_index; i++)
                                                            {
                                                                indexes.Add(i);
                                                            }
                                                        }
                                                    }
                                                }
                                                else if (to_parts.Length == 2) // 24:35-"27:62"
                                                {
                                                    int to_verse_number_in_chapter;
                                                    if (int.TryParse(to_parts[0], out to_chapter_number))
                                                    {
                                                        if (int.TryParse(to_parts[1], out to_verse_number_in_chapter))
                                                        {
                                                            if (from_chapter_number <= to_chapter_number)  // 24:XX-27:XX // only worry about chapters
                                                            {
                                                                Chapter from_chapter = null;
                                                                foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                                {
                                                                    if (book_chapter.Number == from_chapter_number)
                                                                    {
                                                                        from_chapter = book_chapter;
                                                                    }
                                                                }
                                                                int from_verse_index = from_chapter.Verses[from_verse_number_in_chapter - 1].Number - 1;
                                                                Chapter to_chapter = null;
                                                                foreach (Chapter book_chapter in m_client.Book.Chapters)
                                                                {
                                                                    if (book_chapter.Number == to_chapter_number)
                                                                    {
                                                                        to_chapter = book_chapter;
                                                                    }
                                                                }
                                                                int to_verse_index = to_chapter.Verses[to_verse_number_in_chapter - 1].Number - 1;
                                                                for (int i = from_verse_index; i <= to_verse_index; i++)
                                                                {
                                                                    indexes.Add(i);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        m_client.Selection = new Selection(m_client.Book, scope, indexes);
                        DisplaySelection(true);
                    }
                }
                catch
                {
                    // log exception
                }
            }
        }

        // reject all other keys
        if (!(SeparatorKeys || NumericKeys || EditKeys || NavigationKeys))
        {
            e.SuppressKeyPress = true;
            e.Handled = true;
        }
    }
    private void ChapterComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            int chapter_index = m_client.Book.Chapters[ChapterComboBox.SelectedIndex].Number - 1;

            if (
                 ChapterComboBox.Focused ||
                 ChapterVerseNumericUpDown.Focused ||
                 PageNumericUpDown.Focused ||
                 StationNumericUpDown.Focused ||
                 PartNumericUpDown.Focused ||
                 GroupNumericUpDown.Focused ||
                 QuarterNumericUpDown.Focused ||
                 BowingNumericUpDown.Focused
             )
            {
                m_client.Selection = new Selection(m_client.Book, SelectionScope.Chapter, new List<int>() { chapter_index });
            }
            else if ((sender == PreviousBookmarkButton) || (sender == NextBookmarkButton))
            {
            }
            else if ((sender == BrowseHistoryBackwardButton) || (sender == BrowseHistoryForwardButton))
            {
            }
            else
            {
            }

            DisplaySelection(false);
            UpdateMinMaxChapterVerseWordLetter(chapter_index);
        }
    }
    private void UpdateMinMaxChapterVerseWordLetter(int chapter_index)
    {
        if (m_client != null)
        {
            if (m_client.Book != null)
            {
                if (m_client.Book.Chapters != null)
                {
                    if ((chapter_index >= 0) && (chapter_index < m_client.Book.Chapters.Count))
                    {
                        Chapter chapter = m_client.Book.Chapters[chapter_index];
                        if (chapter != null)
                        {
                            try
                            {
                                ChapterVerseNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                                ChapterVerseNumericUpDown.Minimum = 1;
                                ChapterVerseNumericUpDown.Maximum = chapter.Verses.Count;
                            }
                            finally
                            {
                                ChapterVerseNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                            }
                        }
                    }
                }
            }
        }
    }

    private void NumericUpDown_Enter(object sender, EventArgs e)
    {
        this.AcceptButton = null;
    }
    private void NumericUpDown_Leave(object sender, EventArgs e)
    {
        this.AcceptButton = null;
    }
    private void NumericUpDown_ValueChanged(object sender, EventArgs e)
    {
        Control control = sender as NumericUpDown;
        if (control != null)
        {
            if (control.Focused)
            {
                DisplayNumericSelection(control, true);
            }
        }
    }
    private void ColorizePositionControls()
    {
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                // Clear BackColors
                ChapterComboBox.BackColor = SystemColors.Window;
                ChapterVerseNumericUpDown.BackColor = SystemColors.Window;
                PageNumericUpDown.BackColor = SystemColors.Window;
                StationNumericUpDown.BackColor = SystemColors.Window;
                PartNumericUpDown.BackColor = SystemColors.Window;
                GroupNumericUpDown.BackColor = SystemColors.Window;
                QuarterNumericUpDown.BackColor = SystemColors.Window;
                BowingNumericUpDown.BackColor = SystemColors.Window;

                switch (m_client.Selection.Scope)
                {
                    case SelectionScope.Book:
                    case SelectionScope.Chapter:
                    case SelectionScope.Verse:
                        {
                            ChapterComboBox.BackColor = Color.FromArgb(255, 255, 192);
                            ChapterVerseNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Page:
                        {
                            PageNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Station:
                        {
                            StationNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Part:
                        {
                            PartNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Group:
                        {
                            GroupNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Quarter:
                        {
                            QuarterNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    case SelectionScope.Bowing:
                        {
                            BowingNumericUpDown.BackColor = Color.FromArgb(255, 255, 192);
                        }
                        break;
                    default: // Unknown
                        {
                            MessageBox.Show("Unknown selection scope.", Application.ProductName);
                        }
                        break;
                }
            }
        }
    }

    private bool m_is_selection_mode = false;
    private void DisplayNumericSelection(Control control, bool add_to_history)
    {
        if (control is NumericUpDown)
        {
            if (control.Focused)
            {
                try
                {
                    ChapterVerseNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    PageNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    StationNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    PartNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    GroupNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    QuarterNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                    BowingNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);

                    int number = (int)((control as NumericUpDown).Value);

                    if (m_client != null)
                    {
                        SelectionScope scope = SelectionScope.Book;

                        if (control == ChapterVerseNumericUpDown)
                        {
                            if (m_client.Book.Verses != null)
                            {
                                scope = SelectionScope.Verse;

                                int chapter_index = ChapterComboBox.SelectedIndex;
                                if (m_client.Book.Chapters != null)
                                {
                                    int verse_number_in_chapter = (int)ChapterVerseNumericUpDown.Value;
                                    if ((chapter_index >= 0) && (chapter_index < m_client.Book.Chapters.Count))
                                    {
                                        Chapter chapter = m_client.Book.Chapters[chapter_index];
                                        if (chapter != null)
                                        {
                                            if (chapter.Verses != null)
                                            {
                                                if (m_client.Book.Chapters[chapter_index].Verses.Count > verse_number_in_chapter - 1)
                                                {
                                                    Verse verse = m_client.Book.Chapters[chapter_index].Verses[verse_number_in_chapter - 1];
                                                    if (verse != null)
                                                    {
                                                        number = verse.Number;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else if (control == PageNumericUpDown)
                        {
                            if (m_client.Book.Pages != null)
                            {
                                scope = SelectionScope.Page;
                            }
                        }
                        else if (control == StationNumericUpDown)
                        {
                            if (m_client.Book.Stations != null)
                            {
                                scope = SelectionScope.Station;
                            }
                        }
                        else if (control == PartNumericUpDown)
                        {
                            if (m_client.Book.Parts != null)
                            {
                                scope = SelectionScope.Part;
                            }
                        }
                        else if (control == GroupNumericUpDown)
                        {
                            if (m_client.Book.Groups != null)
                            {
                                scope = SelectionScope.Group;
                            }
                        }
                        else if (control == QuarterNumericUpDown)
                        {
                            if (m_client.Book.Quarters != null)
                            {
                                scope = SelectionScope.Quarter;
                            }
                        }
                        else if (control == BowingNumericUpDown)
                        {
                            if (m_client.Book.Bowings != null)
                            {
                                scope = SelectionScope.Bowing;
                            }
                        }
                        else
                        {
                            // do nothing
                        }

                        // if selection has changed
                        if (
                            (m_client.Selection.Scope != scope)
                            ||
                            ((m_client.Selection.Indexes.Count > 0) && (m_client.Selection.Indexes[0] != (number - 1)))
                           )
                        {
                            List<int> indexes = new List<int>() { number - 1 };
                            m_client.Selection = new Selection(m_client.Book, scope, indexes);
                            DisplaySelection(add_to_history);
                        }
                    }
                }
                finally
                {
                    ChapterVerseNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    PageNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    StationNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    PartNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    GroupNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    QuarterNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                    BowingNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                }
            }
        }
    }
    private void DisplaySelection(bool add_to_history)
    {
        this.Cursor = Cursors.WaitCursor;
        MainTextBox.BeginUpdate();

        try
        {
            BookmarkTextBox.Enabled = true;

            if (m_client != null)
            {
                if (m_client.Selection != null)
                {
                    m_current_line_index = 0; // 0 to get a valid verse from GetVerse(..)
                    m_is_selection_mode = true;
                    m_found_verses_displayed = false;

                    UpdateHeaderLabel();

                    MainTextBox.BackColor = SystemColors.Info;
                    TranslationTextBox.BackColor = SystemColors.Info;
                    DisplaySelectionText();
                    DisplaySelectionPositions();

                    MainTextBox.AlignToStart();

                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses != null)
                    {
                        DisplayTranslation(verses);
                        if (verses.Count > 0)
                        {
                            if (add_to_history)
                            {
                                AddSelectionHistoryItem();
                            }
                        }
                    }

                    // display selection's note (if any)
                    DisplayNote(m_client.GetBookmark(m_client.Selection));
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            MainTextBox.EndUpdate();
            this.Cursor = Cursors.Default;
        }
    }
    private void DisplaySelectionText()
    {
        this.Cursor = Cursors.WaitCursor;
        MainTextBox.BeginUpdate();

        try
        {
            if (m_client != null)
            {
                if (m_client.Selection != null)
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    StringBuilder str = new StringBuilder();
                    if (verses != null)
                    {
                        foreach (Verse verse in verses)
                        {
                            str.Append(verse.Text + verse.Endmark);
                        }
                        // remove trailing Endmark
                        if (verses.Count > 0)
                        {
                            if (MainTextBox.WordWrap)
                            {
                                str.Remove(str.Length - 1, 1); // last space in " {###} "
                            }
                            else
                            {
                                str.Remove(str.Length - 2, 2); // \r\n
                            }
                        }
                    }
                    m_current_text = str.ToString();
                    MainTextBox.Text = m_current_text;
                }
            }
        }
        finally
        {
            MainTextBox.EndUpdate();
            this.Cursor = Cursors.Default;
        }
    }
    private void RefreshLanguageType(string text)
    {
        if (text.IsArabic())
        {
            m_find_by_text_language_type = FindByTextLanguageType.Arabic;
        }
        else
        {
            m_find_by_text_language_type = FindByTextLanguageType.Translation;
        }
    }
    private void DisplaySelectionPositions()
    {
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                List<Verse> verses = m_client.Selection.Verses;
                if (verses != null)
                {
                    if (verses.Count > 0)
                    {
                        Verse verse = verses[0];
                        if (verse != null)
                        {
                            // show postion of verse in the Quran visually
                            ProgressBar.Minimum = Verse.MIN_NUMBER;
                            ProgressBar.Maximum = Verse.MAX_NUMBER;
                            ProgressBar.Value = verse.Number;
                            ProgressBar.Refresh();

                            if (ChapterComboBox.Items.Count > 0)
                            {
                                DisplayChapter(verse.Chapter);
                                RefreshChapterSelection();
                            }
                            UpdateVersePositions(verse);

                            UpdateHeaderLabel();

                            Bookmark bookmark = m_client.GotoBookmark(m_client.Selection.Scope, m_client.Selection.Indexes);
                            if (bookmark != null)
                            {
                                BookmarkTextBox.ForeColor = m_note_view_color;
                                BookmarkTextBox.Text = bookmark.Note;
                                string hint = "Creation Time" + "\t" + bookmark.CreatedTime + "\r\n"
                                            + "Last Modified" + "\t" + bookmark.LastModifiedTime;
                                ToolTip.SetToolTip(BookmarkTextBox, hint);
                                UpdateBookmarkHistoryButtons();
                            }
                            else
                            {
                                DisplayNoteWritingInstruction();
                            }
                        }
                    }
                }
            }
        }
    }
    private void DisplayCurrentPositions()
    {
        if (MainTextBox.Lines.Length > 0)
        {
            Verse verse = GetCurrentVerse();
            if (verse != null)
            {
                if (verse.Chapter != null)
                {
                    // show postion of verse in the Quran visually
                    ProgressBar.Minimum = Verse.MIN_NUMBER;
                    ProgressBar.Maximum = Verse.MAX_NUMBER;
                    ProgressBar.Value = verse.Number;
                    ProgressBar.Refresh();

                    if (ChapterComboBox.Items.Count > 0)
                    {
                        DisplayChapter(verse.Chapter);
                        RefreshChapterSelection();
                    }
                    UpdateVersePositions(verse);

                    DisplayTranslation(verse);
                    UpdateHeaderLabel();
                }
            }
        }
    }
    private void UpdateVersePositions(Verse verse)
    {
        if (verse != null)
        {
            try
            {
                ChapterComboBox.SelectedIndexChanged -= new EventHandler(ChapterComboBox_SelectedIndexChanged);
                ChapterVerseNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                PageNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                StationNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                PartNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                GroupNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                QuarterNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);
                BowingNumericUpDown.ValueChanged -= new EventHandler(NumericUpDown_ValueChanged);

                if (verse.Chapter != null)
                {
                    ChapterComboBox.SelectedIndex = verse.Chapter.Number - 1;
                }

                if ((verse.NumberInChapter >= Verse.MIN_NUMBER) && (verse.NumberInChapter <= Verse.MAX_NUMBER))
                {
                    if (verse.Chapter != null)
                    {
                        ChapterVerseNumericUpDown.Minimum = 1;
                        ChapterVerseNumericUpDown.Maximum = verse.Chapter.Verses.Count;
                        ChapterVerseNumericUpDown.Value = (verse.NumberInChapter > ChapterVerseNumericUpDown.Maximum) ? ChapterVerseNumericUpDown.Maximum : verse.NumberInChapter;
                    }
                }

                if (verse.Page != null)
                {
                    PageNumericUpDown.Value = verse.Page.Number;
                }
                if (verse.Station != null)
                {
                    StationNumericUpDown.Value = verse.Station.Number;
                }
                if (verse.Part != null)
                {
                    PartNumericUpDown.Value = verse.Part.Number;
                }
                if (verse.Group != null)
                {
                    GroupNumericUpDown.Value = verse.Group.Number;
                }
                if (verse.Quarter != null)
                {
                    QuarterNumericUpDown.Value = verse.Quarter.Number;
                }
                if (verse.Bowing != null)
                {
                    BowingNumericUpDown.Value = verse.Bowing.Number;
                }

                ColorizePositionControls();

                // update player buttons
                int char_index = MainTextBox.SelectionStart;
                int line_index = MainTextBox.GetLineFromCharIndex(char_index);
                PlayerPreviousLabel.Enabled = (line_index > 0);
                PlayerNextLabel.Enabled = (line_index < (MainTextBox.Lines.Length - 1));
            }
            catch
            {
                // ignore poosible error due to non-Arabic search result
                // showing verses with more words than the words in the Arabic verse
                // and throwing exception when assigned to WordNumericUpDown.Value or LetterNumericUpDown.Value
            }
            finally
            {
                ChapterComboBox.SelectedIndexChanged += new EventHandler(ChapterComboBox_SelectedIndexChanged);
                ChapterVerseNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                PageNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                StationNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                PartNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                GroupNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                QuarterNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
                BowingNumericUpDown.ValueChanged += new EventHandler(NumericUpDown_ValueChanged);
            }
        }
    }

    private string m_find_result_header = "";
    private void UpdateHeaderLabel()
    {
        if (m_client != null)
        {
            if (m_found_verses_displayed)
            {
                if (m_client.FoundVerses != null)
                {
                    int number = m_client.FoundVerses.Count;
                    if (m_find_by_text_search_type != FindByTextSearchType.Proximity)
                    {
                        if (m_client.FoundPhrases != null)
                        {
                            number = m_client.FoundPhrases.Count;
                        }
                    }
                    HeaderLabel.Text = m_find_result_header;
                    HeaderLabel.Refresh();
                }
            }
            else
            {
                if (m_client.Selection != null)
                {
                    if (m_client.Selection.Verses.Count > 0)
                    {
                        Verse verse = GetCurrentVerse();
                        if (verse != null)
                        {
                            if (verse.Chapter != null)
                            {
                                HeaderLabel.Text = verse.Chapter.Name
                                          + "  - " + verse.NumberInChapter
                                          + " -   "
                                    //+ "   منزل " + verse.Station.Number
                                          + "    جزء " + verse.Part.Number
                                          + "    حزب " + verse.Group.Number
                                          + "    ربع " + verse.Quarter.Number
                                    //+ "   ركوع " + verse.Bowing.Number
                                          + "    "
                                          + "   صفحة " + verse.Page.Number
                                          ;
                                HeaderLabel.Refresh();
                            }
                        }
                    }
                }
            }
        }
    }

    private void UpdateChapterSelection()
    {
        SelectionScope scope = SelectionScope.Chapter;
        List<int> indexes = new List<int>();
        for (int i = 0; i < ChaptersListBox.SelectedIndices.Count; i++)
        {
            int index = ChaptersListBox.SelectedIndices[i];
            Chapter chapter = m_client.Book.Chapters[index];
            if (chapter != null)
            {
                indexes.Add(chapter.Number - 1);
            }
        }
        m_client.Selection = new Selection(m_client.Book, scope, indexes);
    }
    private void RefreshChapterSelection()
    {
        // many methods call this method so we need a guard
        // without this guard, we cannot select more than 1 chapter in ChaptersListBox
        if (ChaptersListBox.Focused) return;
        // and we cannot move backward/forward when inside the ChaptersListBox using Backspace key

        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                List<Chapter> selected_chapters = m_client.Selection.Chapters;

                // add the chapters to the ChaptersListBox
                try
                {
                    ChaptersListBox.SelectedIndexChanged -= new EventHandler(ChaptersListBox_SelectedIndexChanged);
                    ChaptersListBox.SelectedIndices.Clear();
                    foreach (Chapter chapter in selected_chapters)
                    {
                        int index = chapter.Number - 1;
                        if ((index >= 0) && (index < ChaptersListBox.Items.Count))
                        {
                            ChaptersListBox.SelectedIndices.Add(index);
                        }
                    }
                }
                finally
                {
                    ChaptersListBox.SelectedIndexChanged += new EventHandler(ChaptersListBox_SelectedIndexChanged);
                }
            }
        }
    }
    private void DisplayChapter(Chapter chapter)
    {
        try
        {
            if (m_client != null)
            {
                // stop circular event firing
                ChapterComboBox.SelectedIndexChanged -= new EventHandler(ChapterComboBox_SelectedIndexChanged);

                if (chapter != null)
                {
                    int chapter_index = chapter.Number - 1;
                    UpdateMinMaxChapterVerseWordLetter(chapter_index);
                    ChapterComboBox.SelectedIndex = chapter_index;
                }
            }
        }
        finally
        {
            ChapterComboBox.SelectedIndexChanged += new EventHandler(ChapterComboBox_SelectedIndexChanged);
        }
    }
    private int m_last_selected_index = -1;
    private void ChaptersListBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (sender == ChaptersListBox)
        {
            if (m_client != null)
            {
                UpdateChapterSelection();
                DisplaySelection(false);
                m_last_selected_index = ChaptersListBox.SelectedIndex;
            }
        }
    }

    // F3 and Shift+F3 Goto next/previous matches
    public struct TextSelection
    {
        public int Start;
        public int Length;
    }
    private List<TextSelection> m_text_selections = new List<TextSelection>();
    private void BuildTextSelection(int start, int length)
    {
        // build text_selections list for F3 and Shift+F3
        TextSelection text_selection = new TextSelection();
        text_selection.Start = start;
        text_selection.Length = length;
        m_text_selections.Add(text_selection);
    }
    private int m_text_selection_index = -1;
    private void GototSelectionIndexBeforeCursor()
    {
        m_text_selection_index = -1;
        for (int i = 0; i < m_text_selections.Count; i++)
        {
            if (m_text_selections[i].Start > MainTextBox.SelectionStart)
            {
                m_text_selection_index = i - 1;
                break;
            }
        }
    }
    private void GotoSelectionIndexAfterCursor()
    {
        m_text_selection_index = m_text_selections.Count;
        for (int i = m_text_selections.Count - 1; i >= 0; i--)
        {
            if (m_text_selections[i].Start < MainTextBox.SelectionStart)
            {
                m_text_selection_index = i + 1;
                break;
            }
        }
    }
    private void FindNextMatch()
    {
        if (m_found_verses_displayed)
        {
            if (m_text_selections != null)
            {
                if (m_text_selections.Count > 0)
                {
                    // find the index prior to the current cursor postion
                    GototSelectionIndexBeforeCursor();
                    m_text_selection_index++;

                    // round robin
                    if (m_text_selection_index == m_text_selections.Count)
                    {
                        m_text_selection_index = 0;
                    }

                    // find next match
                    if ((m_text_selection_index >= 0) && (m_text_selection_index < m_text_selections.Count))
                    {
                        int start = m_text_selections[m_text_selection_index].Start;
                        int length = m_text_selections[m_text_selection_index].Length;
                        if ((start >= 0) && (start < MainTextBox.Text.Length))
                        {
                            MainTextBox.Select(start, length);
                            MainTextBox.SelectionColor = Color.Red;
                        }
                    }
                }
            }
        }
        RefreshApplicationCaption();
    }
    private void FindPreviousMatch()
    {
        if (m_found_verses_displayed)
        {
            if (m_text_selections != null)
            {
                if (m_text_selections.Count > 0)
                {
                    // find the index after the current cursor postion
                    GotoSelectionIndexAfterCursor();
                    m_text_selection_index--;

                    // round robin
                    if (m_text_selection_index < 0)
                    {
                        m_text_selection_index = m_text_selections.Count - 1;
                    }

                    // find previous match
                    if ((m_text_selection_index >= 0) && (m_text_selection_index < m_text_selections.Count))
                    {
                        int start = m_text_selections[m_text_selection_index].Start;
                        int length = m_text_selections[m_text_selection_index].Length;
                        if ((start >= 0) && (start < MainTextBox.Text.Length))
                        {
                            MainTextBox.Select(start, length);
                            MainTextBox.SelectionColor = Color.Red;
                        }
                    }
                }
            }
        }
        RefreshApplicationCaption();
    }
    private void RefreshApplicationCaption()
    {
        string caption = this.Text;
        int pos = caption.IndexOf(CAPTION_SEPARATOR);
        if (pos > -1)
        {
            caption = caption.Substring(0, pos);
        }

        if (m_found_verses_displayed)
        {
            caption += CAPTION_SEPARATOR + " Match " + ((m_text_selection_index + 1) + "/" + m_text_selections.Count);
        }
        else
        {
            //caption += CAPTION_SEPARATOR;
        }

        this.Text = caption;
    }

    private int m_current_line_index = -1;
    private int m_found_verses_current_line_index = -1;
    private int GetCurrentLineIndex()
    {
        int char_index = MainTextBox.SelectionStart;
        int line_index = MainTextBox.GetLineFromCharIndex(char_index);
        return line_index;
    }
    private bool GotoLine(int line_index)
    {
        if (m_client != null)
        {
            if (line_index >= 0)
            {
                int index = MainTextBox.GetFirstCharIndexFromLine(line_index);
                if ((index >= 0) && (index < MainTextBox.Text.Length))
                {
                    //MainTextBox.Focus();
                    MainTextBox.Select(index, 0);
                    MainTextBox.Refresh();

                    Verse verse = GetCurrentVerse();
                    UpdateVersePositions(verse);

                    return true;
                }
            }
        }
        return false;
    }
    private bool GotoNextLine()
    {
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                // reset first verse to -1 on new selection
                if (m_is_selection_mode)
                {
                    if (m_found_verses_displayed)
                    {
                        if (m_found_verses_current_line_index == 0)
                        {
                            m_found_verses_current_line_index--;
                        }
                    }
                    else
                    {
                        if (m_current_line_index == 0)
                        {
                            m_current_line_index--;
                        }
                    }
                    m_is_selection_mode = false;
                }

                // go to next line
                if (m_found_verses_displayed)
                {
                    m_found_verses_current_line_index++;
                }
                else
                {
                    m_current_line_index++;
                }

                int line_index = -1;
                if (m_found_verses_displayed)
                {
                    line_index = m_found_verses_current_line_index;
                }
                else
                {
                    line_index = m_current_line_index;
                }
                return GotoLine(line_index);
            }
        }
        return false;
    }
    private Verse GetCurrentVerse()
    {
        return GetVerseAtCursor();
    }
    private Verse GetVerseAtCursor()
    {
        Verse verse = null;
        int char_index = MainTextBox.SelectionStart;
        int line_index = MainTextBox.GetLineFromCharIndex(char_index);
        if (MainTextBox.WordWrap)
        {
            verse = GetVerseAtChar(char_index);
        }
        else
        {
            verse = GetVerseAtLine(line_index);
        }
        return verse;
    }
    private Word GetWordAtCursor()
    {
        Word word = null;
        int char_index = MainTextBox.SelectionStart;
        int line_index = MainTextBox.GetLineFromCharIndex(char_index);
        if (MainTextBox.WordWrap)
        {
            word = GetWordAtChar(char_index);
        }
        else
        {
            word = GetWordAtLine(line_index, char_index);
        }
        return word;
    }
    private Verse GetVerseAtPointer(MouseEventArgs e)
    {
        Verse verse = null;
        Point mouse_location = e.Location;
        int char_index = MainTextBox.GetCharIndexFromPosition(mouse_location);
        int line_index = MainTextBox.GetLineFromCharIndex(char_index);
        if (MainTextBox.WordWrap)
        {
            verse = GetVerseAtChar(char_index);
        }
        else
        {
            verse = GetVerseAtLine(line_index);
        }
        return verse;
    }
    private Word GetWordAtPointer(MouseEventArgs e)
    {
        Word word = null;
        Point mouse_location = e.Location;
        int char_index = MainTextBox.GetCharIndexFromPosition(mouse_location);
        int line_index = MainTextBox.GetLineFromCharIndex(char_index);
        if (MainTextBox.WordWrap)
        {
            word = GetWordAtChar(char_index);
        }
        else
        {
            word = GetWordAtLine(line_index, char_index);
        }
        return word;
    }
    private Verse GetVerseAtLine(int line_index)
    {
        Verse verse = null;
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_found_verses_displayed)
                {
                    if (m_client.FoundVerses != null)
                    {
                        if ((line_index >= 0) && (line_index < m_client.FoundVerses.Count))
                        {
                            m_found_verses_current_line_index = line_index;
                            verse = m_client.FoundVerses[line_index];
                        }
                    }
                }
                else // m_curent_verses displayed
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses != null)
                    {
                        if ((line_index >= 0) && (line_index < verses.Count))
                        {
                            m_current_line_index = line_index;
                            verse = verses[line_index];
                        }
                    }
                }
            }
        }
        return verse;
    }
    private Verse GetVerseAtChar(int char_index)
    {
        char_index++; // to show verse info when inside verse not before

        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_found_verses_displayed)
                {
                    List<Verse> verses = m_client.FoundVerses;
                    if (verses != null)
                    {
                        foreach (Verse verse in verses)
                        {
                            if (char_index > (verse.ArabicAddress.Length + 1 + verse.Text.Length + 1))
                            {//               CC_VVV                      \t                      \n
                                char_index -= verse.ArabicAddress.Length + 1 + verse.Text.Length + 1;
                            }
                            else
                            {
                                return verse;
                            }
                        }
                    }
                }
                else
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses != null)
                    {
                        foreach (Verse verse in verses)
                        {
                            if (char_index > (verse.Text.Length + verse.Endmark.Length))
                            {
                                char_index -= verse.Text.Length + verse.Endmark.Length;
                            }
                            else
                            {
                                return verse;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    //TODO
    private Word GetWordAtChar(int char_index)
    {
        char_index--; // to show word info when inside word not after the last letter of the previous word

        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_found_verses_displayed)
                {
                    List<Verse> verses = m_client.FoundVerses;
                    if (verses != null)
                    {
                        foreach (Verse verse in verses)
                        {
                            if (char_index > (verse.ArabicAddress.Length + 1 + verse.Text.Length + 1))
                            {//               CC_VVV                      \t                      \n
                                char_index -= verse.ArabicAddress.Length + 1 + verse.Text.Length + 1;
                            }
                            else
                            {
                                // remove verse address
                                char_index -= verse.ArabicAddress.Length + 1; // \t

                                int word_index = CalculateWordIndex(verse, char_index);
                                if ((word_index >= 0) && (word_index < verse.Words.Count))
                                {
                                    return verse.Words[word_index];
                                }
                            }
                        }
                    }
                }
                else
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses != null)
                    {
                        foreach (Verse verse in verses)
                        {
                            if ((char_index >= verse.Text.Length) && (char_index < (verse.Text.Length + verse.Endmark.Length - 1)))
                            {
                                return null; // no word at verse Endmark
                            }

                            if (char_index >= verse.Text.Length)
                            {
                                char_index -= verse.Text.Length + verse.Endmark.Length;
                            }
                            else
                            {
                                int word_index = CalculateWordIndex(verse, char_index);
                                if ((word_index >= 0) && (word_index < verse.Words.Count))
                                {
                                    return verse.Words[word_index];
                                }
                            }
                        }
                    }
                }
            }
        }
        return null;
    }
    private Word GetWordAtLine(int line_index, int char_index)
    {
        char_index--; // to show word info when inside word not after the last letter of the previous word

        if (m_client != null)
        {
            if (char_index >= 0)
            {
                Verse verse = GetVerseAtLine(line_index);
                if (verse != null)
                {
                    int column_index = CalculateColumnIndex(char_index, line_index);
                    int word_index = CalculateWordIndex(verse, column_index);
                    if ((word_index >= 0) && (word_index < verse.Words.Count))
                    {
                        return verse.Words[word_index];
                    }
                }
            }
        }
        return null;
    }
    private int CalculateColumnIndex(int char_index, int line_index)
    {
        int result = char_index;
        if (m_client != null)
        {
            if (m_client.Selection != null)
            {
                if (m_found_verses_displayed)
                {
                    if (m_client.FoundVerses != null)
                    {
                        if (m_client.FoundVerses.Count > 0)
                        {
                            for (int i = 0; i < line_index; i++)
                            {
                                if (i < m_client.FoundVerses.Count)
                                {
                                    result -= m_client.FoundVerses[i].ArabicAddress.Length + 1 + m_client.FoundVerses[i].Text.Length + 1;
                                }
                            }
                            // skip the address at the beginning of the current verse
                            if ((line_index >= 0) && (line_index < m_client.FoundVerses.Count))
                            {
                                result -= m_client.FoundVerses[line_index].ArabicAddress.Length + 1; // \t
                            }
                        }
                    }
                }
                else
                {
                    List<Verse> verses = m_client.Selection.Verses;
                    if (verses != null)
                    {
                        for (int i = 0; i < line_index; i++)
                        {
                            if (i < verses.Count)
                            {
                                result -= verses[i].Text.Length + 1;
                            }
                        }
                    }
                }
            }
        }
        return result;
    }
    private int CalculateWordIndex(Verse verse, int column_index)
    {
        int result = 0;
        if (m_client != null)
        {
            if (verse != null)
            {
                string[] word_texts = verse.Text.Split(' ');
                foreach (string word_text in word_texts)
                {
                    // skip stop marks (1-letter words), except real Quranic 1-letter words
                    if ((word_text.Length == 1) && (word_text != "ص") && (word_text != "ق") && (word_text != "ن"))
                    {
                        // skip stop_mark words
                        column_index -= word_text.Length + 1; // 1 for space
                    }
                    else
                    {
                        if (column_index < word_text.Length)
                        {
                            break;
                        }
                        result++;
                        column_index -= word_text.Length + 1; // 1 for space
                    }
                }
            }
        }
        return result;
    }
    private string RemoveVerseAddresses(string text)
    {
        if (string.IsNullOrEmpty(text)) return "";

        string[] lines = text.Split('\n');
        StringBuilder str = new StringBuilder();
        foreach (string line in lines)
        {
            if (!string.IsNullOrEmpty(line))
            {
                string[] line_parts = line.Split('\t'); // (TAB delimited)
                if (line_parts.Length > 1) // has address
                {
                    str.Append(line_parts[1] + "\n");  // remove verse address
                }
                else if (line_parts.Length > 0)
                {
                    str.Append(line_parts[0] + "\n");  // leave it as it is
                }
            }
        }
        // remove last newline
        if (str.Length > 1)
        {
            str.Remove(str.Length - 1, 1);
        }
        return str.ToString();
    }
    private string RemoveVerseEndMarks(string text)
    {
        // RTL script misplaces brackets
        return text; // do nothing for now

        if (string.IsNullOrEmpty(text)) return "";
        while (text.Contains(Verse.OPEN_BRACKET) || text.Contains(Verse.CLOSE_BRACKET)) // F11 WordWrap
        {
            int start = text.IndexOf(Verse.OPEN_BRACKET);
            int end = text.IndexOf(Verse.CLOSE_BRACKET);
            if ((start >= 0) && (end >= 0))
            {
                if (start < end)
                {
                    text = text.Remove(start, (end - start) + 1); // remove space after it
                }
                else // Arabic script misplaces brackets
                {
                    text = text.Remove(end, (start - end) + 1); // remove space after it
                }
            }
        }
        return text;
    }

    private string CalculateCurrentText()
    {
        string result = "";
        if (m_is_selection_mode)
        {
            result = MainTextBox.Text;
        }
        else
        {
            if (MainTextBox.SelectedText.Length == 0) // get text at current line
            {
                if (Verse.IncludeNumber) // F11 WordWrap
                {
                    result = MainTextBox.Text;
                }
                else // no F11 WordWrap
                {
                    int line_index = GetCurrentLineIndex();
                    if (MainTextBox.Lines.Length > line_index)
                    {
                        result = MainTextBox.Lines[line_index];
                    }
                }
            }
            else // get current text
            {
                result = MainTextBox.SelectedText;
            }
        }
        result = RemoveVerseAddresses(result);
        result = RemoveVerseEndMarks(result);
        result = result.Trim();

        return result;
    }

    private void AddFindHistoryItem()
    {
        if (m_client != null)
        {
            if (m_client.FoundVerses != null)
            {
                if (m_client.FoundVerses.Count > 0)
                {
                    FindHistoryItem item = new FindHistoryItem();
                    item.Text = FindByTextTextBox.Text;
                    item.LanguageType = m_find_by_text_language_type;

                    if (TranslatorComboBox.SelectedItem != null)
                    {
                        item.Translation = TranslatorComboBox.SelectedItem.ToString();
                    }

                    item.Verses = new List<Verse>(m_client.FoundVerses);
                    if (m_client.FoundPhrases == null)
                    {
                        item.Phrases = null;
                    }
                    else
                    {
                        item.Phrases = new List<Phrase>(m_client.FoundPhrases);
                    }
                    item.Header = m_find_result_header;
                    m_client.AddHistoryItem(item);
                    UpdateBrowseHistoryButtons();
                }
            }
        }
    }
    private void AddSelectionHistoryItem()
    {
        if (m_client != null)
        {
            if ((m_client.Book != null) && (m_client.Selection != null))
            {

                SelectionHistoryItem item = new SelectionHistoryItem(m_client.Selection.Book, m_client.Selection.Scope, m_client.Selection.Indexes);
                if (item != null)
                {
                    m_client.AddHistoryItem(item);
                    UpdateBrowseHistoryButtons();
                }
            }
        }
    }
    private void BrowseHistoryBackwardButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            object item = m_client.GotoPreviousHistoryItem();
            if (item != null)
            {
                if (item is FindHistoryItem)
                {
                    m_text_selections.Clear(); // to reset Matched count
                }
                else if (item is SelectionHistoryItem)
                {
                    RefreshChapterSelection();
                }

                DisplayBrowseHistoryItem(item);
                UpdateBrowseHistoryButtons();
            }
        }
        this.AcceptButton = null;
    }
    private void BrowseHistoryForwardButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            object item = m_client.GotoNextHistoryItem();
            if (item != null)
            {
                if (item is FindHistoryItem)
                {
                    m_text_selections.Clear(); // to reset Matched count
                }
                else if (item is SelectionHistoryItem)
                {
                    RefreshChapterSelection();
                }

                DisplayBrowseHistoryItem(item);
                UpdateBrowseHistoryButtons();
            }
        }
        this.AcceptButton = null;
    }
    private void BrowseHistoryDeleteButton_Click(object sender, EventArgs e)
    {
        if (m_client != null)
        {
            m_client.DeleteCurrentHistoryItem();
            if (m_client.HistoryItems.Count == 0) // no item to display
            {
                DisplaySelection(false);
            }
            else // there is an item to display
            {
                object item = m_client.CurrentHistoryItem;
                if (item != null)
                {
                    RefreshChapterSelection();
                    DisplayBrowseHistoryItem(item);
                }
            }

            UpdateBrowseHistoryButtons();
        }
    }
    private void BrowseHistoryClearButton_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show(
            "Delete all browsing and find history?",
            Application.ProductName,
            MessageBoxButtons.YesNo,
            MessageBoxIcon.Question) == DialogResult.Yes)
        {
            if (m_client != null)
            {
                m_client.ClearHistoryItems();
                DisplaySelection(false);

                RefreshChapterSelection();
                UpdateBrowseHistoryButtons();
            }
        }
    }
    private void DisplayBrowseHistoryItem(object item)
    {
        if (m_client != null)
        {
            FindHistoryItem find_history_item = item as FindHistoryItem;
            if (find_history_item != null)
            {
                m_find_result_header = find_history_item.Header;

                m_find_by_text_language_type = find_history_item.LanguageType;

                TranslatorComboBox.SelectedItem = find_history_item.Translation;

                if (find_history_item.Phrases == null)
                {
                    m_client.FoundPhrases = null;
                }
                else
                {
                    m_client.FoundPhrases = new List<Phrase>(find_history_item.Phrases);
                }

                m_client.FoundVerses = new List<Verse>(find_history_item.Verses);
                DisplayFoundVerses(false, false);
            }
            else
            {
                SelectionHistoryItem selection_history_item = item as SelectionHistoryItem;
                if (selection_history_item != null)
                {
                    m_client.Selection = new Selection(selection_history_item.Book, selection_history_item.Scope, selection_history_item.Indexes);
                    DisplaySelection(false);
                }
            }
        }
    }
    private void UpdateBrowseHistoryButtons()
    {
        if (m_client.HistoryItems != null)
        {
            BrowseHistoryBackwardButton.Enabled = (m_client.HistoryItems.Count > 0) && (m_client.HistoryItemIndex > 0);
            BrowseHistoryForwardButton.Enabled = (m_client.HistoryItems.Count >= 0) && (m_client.HistoryItemIndex < m_client.HistoryItems.Count - 1);
            BrowseHistoryDeleteButton.Enabled = (m_client.HistoryItems.Count > 0);
            BrowseHistoryClearButton.Enabled = (m_client.HistoryItems.Count > 0);
            BrowseHistoryClearButton.BackColor = (m_client.HistoryItems.Count > 0) ? Color.LightCoral : SystemColors.ControlLight;
            BrowseHistoryCounterLabel.Text = (m_client.HistoryItemIndex + 1).ToString() + " / " + m_client.HistoryItems.Count.ToString();
        }
    }
    private void BrowseHistoryCounterLabel_Click(object sender, EventArgs e)
    {
        if (m_client.HistoryItems.Count > 0)
        {
            DisplayBrowseHistoryItem(m_client.CurrentHistoryItem);
        }
    }

    private void DisplayFoundVerses(bool add_to_history, bool update_phrase_positions)
    {
        this.Cursor = Cursors.WaitCursor;
        MainTextBox.BeginUpdate();
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);

        try
        {
            BookmarkTextBox.Enabled = false;

            if (m_client != null)
            {
                if (m_client.FoundVerses != null)
                {
                    TranslationTextBox.Text = "";
                    ZoomInLabel.Enabled = (m_text_zoom_factor <= (m_max_zoom_factor - m_zoom_factor_increment + m_error_margin));
                    ZoomOutLabel.Enabled = (m_text_zoom_factor >= (m_min_zoom_factor + m_zoom_factor_increment - m_error_margin));

                    m_current_text = "";
                    if (m_client.FoundVerses.Count > 0)
                    {
                        StringBuilder str = new StringBuilder();
                        foreach (Verse verse in m_client.FoundVerses)
                        {
                            //string verse_address = (m_find_by_text_language_type == FindByTextLanguageType.Arabic) ? verse.ArabicAddress : verse.PaddedAddress;
                            string verse_address = verse.ArabicAddress;
                            if (verse.Chapter != null)
                            {
                                str.Append(verse_address + "\t" + verse.Text + "\n");
                            }
                        }
                        if (str.Length > 0)
                        {
                            str.Remove(str.Length - 1, 1);
                        }
                        m_current_text = str.ToString();
                    }

                    MainTextBox.BackColor = Color.AliceBlue;
                    TranslationTextBox.BackColor = Color.AliceBlue;
                    MainTextBox.Text = m_current_text;

                    m_found_verses_current_line_index = 0; // 0 to get a valid verse from GetVerse(..)
                    m_is_selection_mode = true;
                    m_found_verses_displayed = true;

                    DisplaySelectionPositions();

                    // if FindByText/Root OR HandleEscape OR BrowseFindHistory
                    if ((m_find_by_text_language_type == FindByTextLanguageType.Arabic) && (m_client.FoundPhrases != null))
                    {
                        ColorizeMatches();
                        BuildTextSelections();
                    }

                    if (!m_client.IsTranslation)
                    {
                        // don't use this because it overwrites the ChapterListBox.SelectedIndex
                        //DisplayCurrentPositions();

                        // use this instead
                        if (m_client.FoundVerses != null)
                        {
                            if (m_client.FoundVerses.Count > 0)
                            {
                                DisplayChapter(m_client.FoundVerses[0].Chapter);
                                UpdateVersePositions(m_client.FoundVerses[0]);
                            }
                        }
                    }
                    DisplayTranslation(m_client.FoundVerses);

                    if ((add_to_history) && (m_client.FoundVerses.Count > 0))
                    {
                        AddFindHistoryItem();
                    }

                    RealignFoundMatchedToStart();

                    UpdateHeaderLabel();
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            MainTextBox.SelectionChanged += new EventHandler(MainTextBox_SelectionChanged);
            MainTextBox.EndUpdate();
            this.Cursor = Cursors.Default;
        }
    }
    private void DisplayFoundChapters(bool add_to_history)
    {
        this.Cursor = Cursors.WaitCursor;
        MainTextBox.BeginUpdate();
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);

        try
        {
            BookmarkTextBox.Enabled = false;

            if (m_client != null)
            {
                if (m_client.FoundChapters != null)
                {
                    TranslationTextBox.Text = "";
                    ZoomInLabel.Enabled = (m_text_zoom_factor <= (m_max_zoom_factor - m_zoom_factor_increment + m_error_margin));
                    ZoomOutLabel.Enabled = (m_text_zoom_factor >= (m_min_zoom_factor + m_zoom_factor_increment - m_error_margin));

                    ChaptersListBox.SelectedIndexChanged -= new EventHandler(ChaptersListBox_SelectedIndexChanged);
                    if (m_client.FoundChapters.Count > 0)
                    {
                        ChaptersListBox.SelectedIndices.Clear();
                        foreach (Chapter chapter in m_client.FoundChapters)
                        {
                            if (((chapter.Number - 1) >= 0) && ((chapter.Number - 1) < ChaptersListBox.Items.Count))
                            {
                                ChaptersListBox.SelectedIndices.Add(chapter.Number - 1);
                            }
                        }
                    }
                    else
                    {
                        ChaptersListBox.SelectedIndices.Clear();
                    }
                    ChaptersListBox.SelectedIndexChanged += new EventHandler(ChaptersListBox_SelectedIndexChanged);

                    m_current_text = "";
                    if (m_client.FoundChapters.Count > 0)
                    {
                        StringBuilder str = new StringBuilder();
                        foreach (Chapter chapter in m_client.FoundChapters)
                        {
                            foreach (Verse verse in chapter.Verses)
                            {
                                //string verse_address = (m_find_by_text_language_type == FindByTextLanguageType.Arabic) ? verse.ArabicAddress : verse.PaddedAddress;
                                string verse_address = verse.ArabicAddress;
                                if (verse.Chapter != null)
                                {
                                    str.Append(verse_address + "\t" + verse.Text + "\n");
                                }
                            }
                        }
                        if (str.Length > 0)
                        {
                            str.Remove(str.Length - 1, 1);
                        }
                        m_current_text = str.ToString();
                    }

                    MainTextBox.BackColor = Color.AliceBlue;
                    TranslationTextBox.BackColor = Color.AliceBlue;
                    MainTextBox.Text = m_current_text;

                    m_found_verses_current_line_index = 0; // 0 to get a valid verse from GetVerse(..)
                    m_is_selection_mode = true;
                    m_found_verses_displayed = true;

                    if (!m_client.IsTranslation)
                    {
                        // don't use this because it overwrites the ChapterListBox.SelectedIndex
                        //DisplayCurrentPositions();

                        // use this instead
                        if (m_client.FoundVerses != null)
                        {
                            if (m_client.FoundVerses.Count > 0)
                            {
                                DisplayChapter(m_client.FoundVerses[0].Chapter);
                                UpdateVersePositions(m_client.FoundVerses[0]);
                            }
                        }
                    }
                    DisplayTranslation(m_client.FoundVerses);

                    if ((add_to_history) && (m_client.FoundChapters.Count > 0))
                    {
                        AddFindHistoryItem();
                    }

                    RealignFoundMatchedToStart();

                    UpdateHeaderLabel();
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            MainTextBox.SelectionChanged += new EventHandler(MainTextBox_SelectionChanged);
            MainTextBox.EndUpdate();
            this.Cursor = Cursors.Default;
        }
    }
    private void RealignFoundMatchedToStart()
    {
        if (m_found_verses_displayed)
        {
            int start = 0;

            // scroll to beginning to show complete verse address as in Arabic, pos=0 is after the first number :(
            if (m_client.FoundVerses.Count > 0)
            {
                Verse verse = m_client.FoundVerses[0];
                if (verse != null)
                {
                    if (verse.Chapter != null)
                    {
                        if (m_find_by_text_language_type == FindByTextLanguageType.Arabic)
                        {
                            if (verse.Chapter != null)
                            {
                                start = verse.Chapter.Number.ToString().Length;
                            }
                        }
                        else // in non-Arabic (actually Left-to-Right languages) text
                        {
                            //start = verse.EnglishAddress.Length;
                            start = verse.Chapter.Number.ToString().Length;
                        }
                    }
                }
            }

            // re-align to text start
            try
            {
                MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
                MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
                MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);

                if ((start >= 0) && (start < MainTextBox.Text.Length))
                {
                    MainTextBox.ScrollToCaret();    // must be first
                    MainTextBox.Select(start, 0);   // must be second
                }
            }
            finally
            {
                MainTextBox.SelectionChanged += new EventHandler(MainTextBox_SelectionChanged);
            }
        }
    }

    private void ColorizeMatches()
    {
        this.Cursor = Cursors.WaitCursor;
        MainTextBox.BeginUpdate();
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);
        MainTextBox.SelectionChanged -= new EventHandler(MainTextBox_SelectionChanged);

        try
        {
            if (m_client != null)
            {
                if (m_client.FoundPhrases != null)
                {
                    if (m_client.FoundPhrases.Count > 0)
                    {
                        foreach (Phrase phrase in m_client.FoundPhrases)
                        {
                            int start = GetPhrasePositionInRichTextBox(phrase);
                            int length = phrase.Text.Length;
                            if ((start >= 0) && (start < MainTextBox.Text.Length))
                            {
                                MainTextBox.Select(start, length);
                                MainTextBox.SelectionColor = Color.Red;
                            }
                        }
                        RealignFoundMatchedToStart();
                        RefreshApplicationCaption();
                    }
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
        finally
        {
            MainTextBox.SelectionChanged += new EventHandler(MainTextBox_SelectionChanged);
            MainTextBox.EndUpdate();
            this.Cursor = Cursors.Default;
        }
    }
    private int GetPhrasePositionInRichTextBox(Phrase phrase)
    {
        if (m_client != null)
        {
            int start = 0;
            foreach (Verse verse in m_client.FoundVerses)
            {
                if (phrase.Verse.Number == verse.Number)
                {
                    if (m_find_by_text_language_type == FindByTextLanguageType.Arabic)
                    {
                        start += verse.ArabicAddress.Length + 1 + phrase.Position;
                    }
                    else if (m_find_by_text_language_type == FindByTextLanguageType.Translation)
                    {
                        //start += verse.EnglishAddress.Length + 1 + phrase.Position;
                        start += verse.ArabicAddress.Length + 1 + phrase.Position;
                    }
                    return start;
                }

                // take into account prior verses
                if (m_find_by_text_language_type == FindByTextLanguageType.Arabic)
                {
                    start += verse.ArabicAddress.Length + 1 + verse.Text.Length + 1; // 1 for \n
                }
                else if (m_find_by_text_language_type == FindByTextLanguageType.Translation)
                {
                    //start += verse.EnglishAddress.Length + 1 + verse.Text.Length + 1; // 1 for \n
                    start += verse.ArabicAddress.Length + 1 + verse.Text.Length + 1; // 1 for \n
                }
            }
        }
        return -1;
    }
    private void BuildTextSelections()
    {
        try
        {
            if (m_client != null)
            {
                if (m_client.FoundPhrases != null)
                {
                    if (m_client.FoundPhrases.Count > 0)
                    {
                        foreach (Phrase phrase in m_client.FoundPhrases)
                        {
                            int start = GetPhrasePositionInRichTextBox(phrase);
                            int length = phrase.Text.Length;
                            BuildTextSelection(start, length);
                        }
                    }
                }
            }
            RefreshApplicationCaption();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName);
        }
    }

    private FindByTextSearchType m_find_by_text_search_type = FindByTextSearchType.Exact;
    FindByTextLanguageType m_find_by_text_language_type = FindByTextLanguageType.Arabic;
    private string RemovePunctuationMarks(string text)
    {
        if (!String.IsNullOrEmpty(text))
        {
            if (m_find_by_text_language_type == FindByTextLanguageType.Translation)
            {
                text = text.Replace(".", "");
                text = text.Replace(",", "");
                text = text.Replace(";", "");
                text = text.Replace(":", "");
                text = text.Replace("?", "");
                text = text.Replace("/", "");
                text = text.Replace(")", "");
                text = text.Replace("(", "");
                text = text.Replace(">", "");
                text = text.Replace("<", "");
                text = text.Replace("[", "");
                text = text.Replace("]", "");
                text = text.Replace("{", "");
                text = text.Replace("}", "");
                text = text.Replace("-", "");
                text = text.Replace("\"", "");
                text = text.Replace("\'", "");
                text = text.Replace("!", "");
                text = text.Replace("`", "");
                text = text.Replace("@", "");
                text = text.Replace("#", "");
                text = text.Replace("$", "");
                text = text.Replace("%", "");
                text = text.Replace("^", "");
                text = text.Replace("&", "");
                text = text.Replace("|", "");
                text = text.Replace("*", "");
                text = text.Replace("=", "");
            }
        }
        return text;
    }
    private void PrepareNewSearch()
    {
        // to prevent controls from disappearing in heavy calculations
        this.Refresh();

        if (m_client != null)
        {
            m_client.FoundPhrases = null;
            m_text_selections.Clear();
            m_text_selection_index = -1;
        }
    }
    private void FindByText()
    {
        if (FindByTextTextBox.Text.Length > 0)
        {
            string text = FindByTextTextBox.Text.Trim();
            if (text.Length > 0)
            {
                m_find_by_text_language_type = FindByTextLanguageType.Translation;
                bool case_sensitive = true;
                if (text.IsArabic())
                {
                    m_find_by_text_language_type = FindByTextLanguageType.Arabic;
                    case_sensitive = false;
                }

                string translation = Client.DEFAULT_TRANSLATION;
                if (TranslatorComboBox.SelectedItem != null)
                {
                    translation = m_client.GetTranslationKey(TranslatorComboBox.SelectedItem.ToString());
                }

                FindByTextLocation text_location = FindByTextLocation.Anywhere;
                FindByTextWordness wordness = FindByTextWordness.Any;
                int multiplicity = -1;
                FindByText(text, m_find_by_text_language_type, translation, text_location, case_sensitive, wordness, multiplicity, false);
            }
        }
    }
    private void FindByText(string text, FindByTextLanguageType language_type, string translation, FindByTextLocation text_location, bool case_sensitive, FindByTextWordness wordness, int multiplicity, bool anywhere_in_word)
    {
        this.Cursor = Cursors.WaitCursor;
        try
        {
            if (m_client != null)
            {
                PrepareNewSearch();

                if (text.Length > 0)
                {
                    m_client.FindPhrases(text, language_type, translation, text_location, case_sensitive, wordness, multiplicity, anywhere_in_word);
                    if (m_client.FoundPhrases != null)
                    {
                        bool display_phrases_count = true;
                        int phrase_count = m_client.FoundPhrases.Count;

                        if ((text_location == FindByTextLocation.AtStart) || (text_location == FindByTextLocation.AtEnd) || (text_location == FindByTextLocation.AllWords) || (text_location == FindByTextLocation.AnyWord))
                        {
                            display_phrases_count = false;  // not to be dispalyed
                        }

                        if (m_client.FoundVerses != null)
                        {
                            int verse_count = m_client.FoundVerses.Count;
                            if (multiplicity == 0)
                            {
                                m_find_result_header = verse_count + ((verse_count == 1) ? " verse" : " verses") + " without " + text + " " + text_location.ToString() + " in " + "Entire Book";
                            }
                            else
                            {
                                m_find_result_header = (display_phrases_count ? phrase_count + " matches in " : "") + verse_count + ((verse_count == 1) ? " verse" : " verses") + " with " + text + " " + text_location.ToString() + " in " + "Entire Book";
                            }

                            DisplayFoundVerses(true, false);
                        }
                    }
                }
            }
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void FindByRoot()
    {
        if (FindByTextTextBox.Text.Length > 0)
        {
            string root = FindByTextTextBox.Text.Trim();
            int multiplicity = -1;
            FindByRoot(root, multiplicity);
        }
    }
    private void FindByRoot(string root, int multiplicity)
    {
        this.Cursor = Cursors.WaitCursor;
        try
        {
            if (m_client != null)
            {
                PrepareNewSearch();

                if (root.Length > 0)
                {
                    m_client.FindPhrases(root, multiplicity);
                    if (m_client.FoundPhrases != null)
                    {
                        if (m_client.FoundVerses != null)
                        {
                            int verse_count = m_client.FoundVerses.Count;
                            int phrase_count = m_client.FoundPhrases.Count;
                            m_find_result_header = ((m_client.FoundPhrases != null) ? phrase_count + " matches in " : "") + verse_count + ((verse_count == 1) ? " verse" : " verses") + ((multiplicity == 0) ? " without " : " with root ") + root + " in " + "Entire Book";

                            DisplayFoundVerses(true, false);
                        }
                    }
                }
            }
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void FindByTextTextBox_TextChanged(object sender, EventArgs e)
    {
        RefreshLanguageType(FindByTextTextBox.Text);
    }
    private void FindByTextTextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (ModifierKeys == Keys.Control)
        {
            if (e.KeyCode == Keys.A)
            {
                if (sender is TextBoxBase)
                {
                    (sender as TextBoxBase).SelectAll();
                }
            }
        }
        else
        {
            if (e.KeyCode == Keys.Enter)
            {
                FindByText();
            }
        }
    }
    private void FindByTextTextBox_KeyPress(object sender, KeyPressEventArgs e)
    {
        FixMicrosoft(sender, e);

        if (e.KeyChar == ' ')
        {
            // if no multi-root search, then prevent space entry
            //if (m_find_by_text_search_type == FindByTextSearchType.Root)
            //{
            //    e.Handled = true; // prevent space in Root search
            //}

            // prevent double spaces
            if (FindByTextTextBox.SelectionStart > 0)
            {
                if (FindByTextTextBox.Text[FindByTextTextBox.SelectionStart - 1] == ' ')
                {
                    e.Handled = true;
                }
            }
        }
    }

    private void LinkLabel_Click(object sender, EventArgs e)
    {
        this.Cursor = Cursors.WaitCursor;
        try
        {
            Control control = (sender as Control);
            if (control != null)
            {
                if (control.Tag != null)
                {
                    if (!String.IsNullOrEmpty(control.Tag.ToString()))
                    {
                        try
                        {
                            System.Diagnostics.Process.Start(control.Tag.ToString());
                        }
                        catch (Exception ex)
                        {
                            while (ex != null)
                            {
                                //Console.WriteLine(ex.Message);
                                MessageBox.Show(ex.Message, Application.ProductName);
                                ex = ex.InnerException;
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            this.Cursor = Cursors.Default;
        }
    }
    private void VersionLabel_Click(object sender, EventArgs e)
    {
        AboutBox m_about_box = new AboutBox();
        m_about_box.ShowDialog(this);
    }

}
